| Total Complexity | 208 |
| Total Lines | 1003 |
| Duplicated Lines | 7.58 % |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like pygameui.SkinableTheme often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # |
||
| 2 | # Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/] |
||
| 3 | # |
||
| 4 | # This file is part of Pygame.UI. |
||
| 5 | # |
||
| 6 | # Pygame.UI is free software; you can redistribute it and/or modify |
||
| 7 | # it under the terms of the Lesser GNU General Public License as published by |
||
| 8 | # the Free Software Foundation; either version 2.1 of the License, or |
||
| 9 | # (at your option) any later version. |
||
| 10 | # |
||
| 11 | # Pygame.UI is distributed in the hope that it will be useful, |
||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 14 | # Lesser GNU General Public License for more details. |
||
| 15 | # |
||
| 16 | # You should have received a copy of the Lesser GNU General Public License |
||
| 17 | # along with Pygame.UI; if not, write to the Free Software |
||
| 18 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||
| 19 | # |
||
| 20 | |||
| 21 | import string |
||
| 22 | import pygame |
||
| 23 | import Const |
||
| 24 | import Fonts |
||
| 25 | import os, os.path, sys, ConfigParser |
||
| 26 | from ige import log |
||
| 27 | import time |
||
| 28 | import resources |
||
| 29 | |||
| 30 | try: |
||
| 31 | import _winreg |
||
| 32 | except ImportError: |
||
| 33 | pass |
||
| 34 | |||
| 35 | skinDir = file = os.path.join(os.path.dirname(sys.modules[__name__].__file__), "DefaultSkin") |
||
| 36 | config = None |
||
| 37 | boxes = {} |
||
| 38 | sounds = {} |
||
| 39 | gridParams = None |
||
| 40 | soundEnabled = True |
||
| 41 | soundVolume = True |
||
| 42 | musicEnabled = True |
||
| 43 | musicVolume = True |
||
| 44 | themeMusic = None |
||
| 45 | |||
| 46 | class Box: |
||
| 47 | """Holds all boxed graphics""" |
||
| 48 | pass |
||
| 49 | |||
| 50 | def init(): |
||
| 51 | global themeMusic |
||
| 52 | try: |
||
| 53 | themeMusic = config.get("general","music") |
||
| 54 | except ConfigParser.Error: |
||
| 55 | themeMusic = None |
||
| 56 | pass |
||
| 57 | # setSkin(skinDir) |
||
| 58 | |||
| 59 | def initMixer(): |
||
| 60 | global soundEnabled |
||
| 61 | global musicEnabled |
||
| 62 | if (soundEnabled == False) and (musicEnabled == False): |
||
| 63 | pygame.mixer.init(44100, -16, 2, 4096) |
||
| 64 | |||
| 65 | def closeMixer(): |
||
| 66 | global soundEnabled |
||
| 67 | global musicEnabled |
||
| 68 | if (soundEnabled == False) and (musicEnabled == False): |
||
| 69 | pygame.mixer.quit() |
||
| 70 | |||
| 71 | def enableSound(enable): |
||
| 72 | global soundEnabled |
||
| 73 | if (enable == True) : |
||
| 74 | initMixer() |
||
| 75 | soundEnabled = enable |
||
| 76 | if (enable == False) : |
||
| 77 | closeMixer() |
||
| 78 | |||
| 79 | def setVolume(volume): |
||
| 80 | global soundVolume |
||
| 81 | soundVolume = volume |
||
| 82 | |||
| 83 | def enableMusic(enable): |
||
| 84 | global musicEnabled |
||
| 85 | if (enable == True) : |
||
| 86 | initMixer() |
||
| 87 | else: |
||
| 88 | closeMixer() |
||
| 89 | musicEnabled = enable |
||
| 90 | if musicEnabled == True: |
||
| 91 | loadMusic(None) |
||
| 92 | playMusic() |
||
| 93 | else: |
||
| 94 | stopMusic() |
||
| 95 | time.sleep(1) |
||
| 96 | closeMixer() |
||
| 97 | |||
| 98 | def setMusicVolume(volume): |
||
| 99 | global musicVolume |
||
| 100 | global musicEnabled |
||
| 101 | musicVolume = volume |
||
| 102 | try: |
||
| 103 | if musicEnabled : |
||
| 104 | pygame.mixer.music.set_volume(volume) |
||
| 105 | except: |
||
| 106 | log.warning("Cannot set music volume") |
||
| 107 | |||
| 108 | def setSkin(directory = skinDir): |
||
| 109 | global skinDir, config, gridParams |
||
| 110 | skinDir = directory |
||
| 111 | # load skin specification |
||
| 112 | config = ConfigParser.ConfigParser() |
||
| 113 | config.read(os.path.join(skinDir, "config.ini")) |
||
| 114 | # grid |
||
| 115 | w, h = config.get("general", "grid").split(",") |
||
| 116 | gridParams = (int(w), int(h)) |
||
| 117 | # basic colors |
||
| 118 | global themeForeground, themeBackground, themeTitleLine1, themeTitleLine2 |
||
| 119 | global themeHighlightbck, themeHighlightfrg, themeCritical, themeMajor |
||
| 120 | global themeMinor, themeNone, themeDisabled, themeIcons |
||
| 121 | global themeMusic |
||
| 122 | themeForeground = hex2color(config.get("general", "foreground")) |
||
| 123 | themeIcons = hex2color(config.get("general", "icons")) |
||
| 124 | themeBackground = hex2color(config.get("general", "background")) |
||
| 125 | themeTitleLine1 = hex2color(config.get("general", "line1")) |
||
| 126 | themeTitleLine2 = hex2color(config.get("general", "line2")) |
||
| 127 | themeHighlightbck = hex2color(config.get("general", "highlightbck")) |
||
| 128 | themeHighlightfrg = hex2color(config.get("general", "highlightfrg")) |
||
| 129 | themeCritical = hex2color(config.get("general", "critical")) |
||
| 130 | themeMajor = hex2color(config.get("general", "major")) |
||
| 131 | themeMinor = hex2color(config.get("general", "minor")) |
||
| 132 | themeNone = hex2color(config.get("general", "none")) |
||
| 133 | themeDisabled = hex2color(config.get("general", "disabled")) |
||
| 134 | try: |
||
| 135 | themeMusic = config.get("general","music") |
||
| 136 | except ConfigParser.Error: |
||
| 137 | themeMusic = None |
||
| 138 | # create elements |
||
| 139 | createFont() |
||
| 140 | for section in config.sections(): |
||
| 141 | if section.endswith("box"): |
||
| 142 | createBox(section) |
||
| 143 | |||
| 144 | def createFont(): |
||
| 145 | # create font |
||
| 146 | for fontName in config.get("general", "fonts").split(","): |
||
| 147 | section = "%s font" % fontName |
||
| 148 | fontType = config.get(section, "type") |
||
| 149 | log.debug("Loading font", fontName, fontType) |
||
| 150 | if fontType == "windowsttf": |
||
| 151 | if os.name == "nt": |
||
| 152 | # get "Fonts" folder location |
||
| 153 | handle = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders') |
||
| 154 | path, valueType = _winreg.QueryValueEx(handle, 'Fonts') |
||
| 155 | handle.Close() |
||
| 156 | filename = os.path.join(path, config.get(section, "file")) |
||
| 157 | else: |
||
| 158 | continue |
||
| 159 | elif fontType == "ttf": |
||
| 160 | filename = resources.get(config.get(section, "file")) |
||
| 161 | elif fontType == "default": |
||
| 162 | filename = None |
||
| 163 | # load font |
||
| 164 | if filename == None or os.path.exists(filename): |
||
|
|
|||
| 165 | Fonts.initFont('small', filename, config.getint(section, "small")) |
||
| 166 | Fonts.initFont('small-bold', filename, config.getint(section, "small"), bold = 1) |
||
| 167 | Fonts.initFont('small-italic', filename, config.getint(section, "small"), italic = 1) |
||
| 168 | Fonts.initFont('normal', filename, config.getint(section, "normal")) |
||
| 169 | Fonts.initFont('normal-bold', filename, config.getint(section, "normal"), bold = 1) |
||
| 170 | Fonts.initFont('normal-italic', filename, config.getint(section, "normal"), italic = 1) |
||
| 171 | Fonts.initFont('large', filename, config.getint(section, "large")) |
||
| 172 | Fonts.initFont('large-bold', filename, config.getint(section, "large"), bold = 1) |
||
| 173 | Fonts.initFont('large-italic', filename, config.getint(section, "large"), italic = 1) |
||
| 174 | return |
||
| 175 | |||
| 176 | def createBox(section): |
||
| 177 | global boxes |
||
| 178 | boxName = section[:-4] |
||
| 179 | for option in config.options(section): |
||
| 180 | if option.startswith("sound-"): |
||
| 181 | createSounds(section, option) |
||
| 182 | continue |
||
| 183 | box = Box() |
||
| 184 | opt = config.get(section, option).split(",") |
||
| 185 | filename, x, y, r, b = opt[:5] |
||
| 186 | foreground, tl, tt, tr, tb = opt[5:] |
||
| 187 | if foreground == "-": |
||
| 188 | box.foreground = None |
||
| 189 | else: |
||
| 190 | box.foreground = hex2color(foreground) |
||
| 191 | box.cMargins = int(tl), int(tt), int(tr), int(tb) |
||
| 192 | # graphical reprezentation |
||
| 193 | x, y, r, b = int(x), int(y), int(r), int(b) |
||
| 194 | box.img = pygame.image.load(os.path.join(skinDir, filename)).convert_alpha() |
||
| 195 | w, h = box.img.get_size() |
||
| 196 | box.margins = x, y, r, b |
||
| 197 | box.rect = pygame.Rect(x, y, w - r, h - b) |
||
| 198 | box.topleft = box.img.subsurface(0, 0, x, y) |
||
| 199 | box.bottomleft = box.img.subsurface(0, h - b, x, b) |
||
| 200 | box.topright = box.img.subsurface(w - r, 0, r, y) |
||
| 201 | box.bottomright = box.img.subsurface(w - r, h - b, r, b) |
||
| 202 | box.top = box.img.subsurface(x, 0, w - r - x, y) |
||
| 203 | box.bottom = box.img.subsurface(x, h - b, w - r - x, b) |
||
| 204 | box.left = box.img.subsurface(0, y, x, h - b - r) |
||
| 205 | box.right = box.img.subsurface(w - r, y, r, h - b - r) |
||
| 206 | box.center = box.img.subsurface(x, y, w - r - x, h - b - y) |
||
| 207 | boxes["%s-%s" % (boxName, option)] = box |
||
| 208 | |||
| 209 | def createSounds(section, option): |
||
| 210 | global sounds |
||
| 211 | name = "%s-%s" % (section[:-4], option[6:]) |
||
| 212 | filename = os.path.join(skinDir, config.get(section, option)) |
||
| 213 | try: |
||
| 214 | sounds[name] = {} |
||
| 215 | sounds[name]["fname"] = filename |
||
| 216 | if soundEnabled: |
||
| 217 | sounds[name]["sound"] = pygame.mixer.Sound(filename) |
||
| 218 | else: |
||
| 219 | sounds[name]["sound"] = None |
||
| 220 | except pygame.error: |
||
| 221 | log.warning("Cannot create sound", name, filename) |
||
| 222 | |||
| 223 | def playSound(style): |
||
| 224 | if soundEnabled and style in sounds: |
||
| 225 | try: |
||
| 226 | if sounds[style]["sound"] == None: |
||
| 227 | filename = sounds[style]["fname"] |
||
| 228 | sounds[style]["sound"] = pygame.mixer.Sound(filename) |
||
| 229 | sounds[style]["sound"].set_volume(soundVolume) |
||
| 230 | sounds[style]["sound"].play() |
||
| 231 | except pygame.error: |
||
| 232 | log.warning("Cannot play sound", style) |
||
| 233 | |||
| 234 | def loadMusic(file): |
||
| 235 | if musicEnabled and pygame.mixer.music.get_busy() == False: |
||
| 236 | global themeMusic |
||
| 237 | if file != None: |
||
| 238 | musicFile = "res.ext/music/" + file |
||
| 239 | elif themeMusic != None: |
||
| 240 | musicFile = "res.ext/music/" + themeMusic |
||
| 241 | else: |
||
| 242 | musicFile = "res.ext/music/riddleofsteel.ogg" |
||
| 243 | if os.path.exists(musicFile): |
||
| 244 | try: |
||
| 245 | pygame.mixer.music.load(musicFile) |
||
| 246 | except pygame.error: |
||
| 247 | log.warning("Cannot load music ",musicFile) |
||
| 248 | |||
| 249 | def playMusic(): |
||
| 250 | if musicEnabled: |
||
| 251 | try: |
||
| 252 | if pygame.mixer.music.get_busy() == False: |
||
| 253 | pygame.mixer.music.play(-1) |
||
| 254 | except pygame.error: |
||
| 255 | log.warning("Cannot play music") |
||
| 256 | |||
| 257 | def stopMusic(): |
||
| 258 | try: |
||
| 259 | if pygame.mixer.music.get_busy() == True: |
||
| 260 | pygame.mixer.music.fadeout(1000) |
||
| 261 | except pygame.error: |
||
| 262 | log.warning("Cannot stop music") |
||
| 263 | except error: |
||
| 264 | pass |
||
| 265 | |||
| 266 | def getGridParams(): |
||
| 267 | return gridParams |
||
| 268 | |||
| 269 | def drawBox(surface, widget, style): |
||
| 270 | box = boxes[style] |
||
| 271 | rect = widget.rect |
||
| 272 | l, t, r, b = box.margins |
||
| 273 | oldClip = surface.get_clip() |
||
| 274 | # corners |
||
| 275 | surface.blit(box.topleft, rect.topleft) |
||
| 276 | surface.blit(box.topright, (rect.right - r, rect.top)) |
||
| 277 | surface.blit(box.bottomleft, (rect.left, rect.bottom - b)) |
||
| 278 | surface.blit(box.bottomright, (rect.right - r, rect.bottom - b)) |
||
| 279 | # center |
||
| 280 | surface.set_clip(rect.left + l, rect.top + t, rect.width - l - r, rect.height - t - b) |
||
| 281 | w, h = box.center.get_size() |
||
| 282 | for x in xrange(rect.left + l, rect.left + rect.width - r -l, w): |
||
| 283 | for y in xrange(rect.top + t, rect.top + rect.height - t - b, h): |
||
| 284 | surface.blit(box.center, (x, y)) |
||
| 285 | # top + bottom |
||
| 286 | surface.set_clip(rect.left + l, rect.top, rect.width - l - r, rect.height) |
||
| 287 | w = box.top.get_width() |
||
| 288 | y1 = rect.top |
||
| 289 | y2 = rect.bottom - b |
||
| 290 | for x in xrange(rect.left + l, rect.left + rect.width - r - l, w): |
||
| 291 | surface.blit(box.top, (x, y1)) |
||
| 292 | surface.blit(box.bottom, [x, y2]) |
||
| 293 | # left + right |
||
| 294 | surface.set_clip(rect.left, rect.top + t, rect.width, rect.height - t - b) |
||
| 295 | h = box.left.get_height() |
||
| 296 | for y in xrange(rect.top + t, rect.top + rect.height - t - b + h, h): |
||
| 297 | surface.blit(box.left, (rect.left, y)) |
||
| 298 | surface.blit(box.right, (rect.right - r, y)) |
||
| 299 | # restore |
||
| 300 | surface.set_clip(oldClip) |
||
| 301 | |||
| 302 | def drawTextAndIcons(surface, widget, style): |
||
| 303 | box = boxes[style] |
||
| 304 | rect = widget.rect |
||
| 305 | l, t, r, b = box.cMargins |
||
| 306 | oldClip = surface.get_clip() |
||
| 307 | rect = pygame.Rect(rect.left + l, rect.top + t, rect.width - l - r, rect.height - t - b) |
||
| 308 | surface.set_clip(rect) |
||
| 309 | # icons |
||
| 310 | if widget.icons: |
||
| 311 | for img, align in widget.icons: |
||
| 312 | r = pygame.Rect(rect) |
||
| 313 | if align & Const.ALIGN_W: |
||
| 314 | rect.left += img.get_width() |
||
| 315 | rect.width -= img.get_width() |
||
| 316 | pass |
||
| 317 | elif align & Const.ALIGN_E: |
||
| 318 | r.left += rect.width - img.get_width() |
||
| 319 | rect.width -= img.get_width() |
||
| 320 | else: |
||
| 321 | r.left += (rect.width - img.get_width()) / 2 |
||
| 322 | if align & Const.ALIGN_N: pass |
||
| 323 | elif align & Const.ALIGN_S: r.top += rect.height - img.get_height() |
||
| 324 | else: r.top += (rect.height - img.get_height()) / 2 |
||
| 325 | surface.blit(img, r) |
||
| 326 | # text |
||
| 327 | if widget.text != None: |
||
| 328 | font = widget.font or themeDefaultFont |
||
| 329 | foreground = box.foreground or widget.foreground or themeForeground |
||
| 330 | background = widget.background |
||
| 331 | |||
| 332 | img = Fonts.renderText(font, widget.text, 1, foreground, background) |
||
| 333 | r = pygame.Rect(rect) |
||
| 334 | if widget.align & Const.ALIGN_W: pass |
||
| 335 | elif widget.align & Const.ALIGN_E: r.left += rect.width - img.get_width() |
||
| 336 | else: r.left += (rect.width - img.get_width()) / 2 |
||
| 337 | if widget.align & Const.ALIGN_N: pass |
||
| 338 | elif widget.align & Const.ALIGN_S: r.top += rect.height - img.get_height() |
||
| 339 | else: r.top += (rect.height - img.get_height()) / 2 |
||
| 340 | surface.blit(img, r) |
||
| 341 | surface.set_clip(oldClip) |
||
| 342 | |||
| 343 | |||
| 344 | def playButtonSound(widget): |
||
| 345 | if widget.pressed: |
||
| 346 | style = "%s-up" % (widget.style or "button") |
||
| 347 | else: |
||
| 348 | style = "%s-down" % (widget.style or "button") |
||
| 349 | playSound(style) |
||
| 350 | |||
| 351 | def drawButton(surface, widget): |
||
| 352 | if not widget.enabled: |
||
| 353 | s2 = "disabled" |
||
| 354 | elif widget.focused: |
||
| 355 | s2 = "focused" |
||
| 356 | else: |
||
| 357 | s2 = "enabled" |
||
| 358 | if widget.pressed: |
||
| 359 | s3 = "down" |
||
| 360 | elif widget.highlighted and widget.enabled: |
||
| 361 | s3 = "highlighted" |
||
| 362 | else: |
||
| 363 | s3 = "up" |
||
| 364 | if widget.toggle: |
||
| 365 | style = "%s-%s-%s" % (widget.style or "togglebutton", s2, s3) |
||
| 366 | else: |
||
| 367 | style = "%s-%s-%s" % (widget.style or "button", s2, s3) |
||
| 368 | drawBox(surface, widget, style) |
||
| 369 | drawTextAndIcons(surface, widget, style) |
||
| 370 | return widget.rect |
||
| 371 | |||
| 372 | def drawCheck(surface, widget): |
||
| 373 | if not widget.enabled: |
||
| 374 | s2 = "disabled" |
||
| 375 | elif widget.focused: |
||
| 376 | s2 = "focused" |
||
| 377 | else: |
||
| 378 | s2 = "enabled" |
||
| 379 | if widget.checked: |
||
| 380 | s3 = "on" |
||
| 381 | else: |
||
| 382 | s3 = "off" |
||
| 383 | style = "%s-%s-%s" % (widget.style or "check", s2, s3) |
||
| 384 | drawBox(surface, widget, style) |
||
| 385 | drawTextAndIcons(surface, widget, style) |
||
| 386 | return widget.rect |
||
| 387 | |||
| 388 | def drawLabel(surface, widget, highlight = 0): |
||
| 389 | if not widget.enabled: |
||
| 390 | style = "%s-disabled" % (widget.style or "label") |
||
| 391 | else: |
||
| 392 | if highlight: |
||
| 393 | style = "%s-highlight" % (widget.style or "label") |
||
| 394 | else: |
||
| 395 | style = "%s-clean" % (widget.style or "label") |
||
| 396 | drawBox(surface, widget, style) |
||
| 397 | drawTextAndIcons(surface, widget, style) |
||
| 398 | return widget.rect |
||
| 399 | |||
| 400 | ## utils |
||
| 401 | def hex2color(text): |
||
| 402 | if len(text) == 8: |
||
| 403 | return int(text[0:2], 16), int(text[2:4], 16), int(text[4:6], 16), int(text[6:8], 16) |
||
| 404 | else: |
||
| 405 | return int(text[0:2], 16), int(text[2:4], 16), int(text[4:6], 16) |
||
| 406 | |||
| 407 | ## |
||
| 408 | ## OLD CODE (for compatibility only) |
||
| 409 | ## |
||
| 410 | |||
| 411 | themeForeground = 0x00, 0xd0, 0x00 |
||
| 412 | # themeWindowBck = 0x20, 0x30, 0x20 |
||
| 413 | themeBackground = 0x20, 0x40, 0x20 |
||
| 414 | themeHighlightbck = 0x40, 0x60, 0x40 |
||
| 415 | themeHighlightfrg = 0x40, 0xf0, 0x40 |
||
| 416 | # themeGaugecolor = 0x00, 0x80, 0x00 |
||
| 417 | themeDefaultFont = 'normal' |
||
| 418 | themeBoldFont = 'normal-bold' |
||
| 419 | themeItalicFont = 'normal-italic' |
||
| 420 | # themeSelectionFrg = 0x00, 0xd0, 0x00 |
||
| 421 | # themeSelectionBck = 0x40, 0x80, 0x40 |
||
| 422 | themeTitleLine1 = 0x30, 0x50, 0x30 |
||
| 423 | themeTitleLine2 = 0x40, 0x60, 0x40 |
||
| 424 | themeSliderMin = 18 |
||
| 425 | themeCritical = 0xFF, 0x80, 0x80 |
||
| 426 | themeMajor = 0xFF, 0xFF, 0x00 |
||
| 427 | themeMinor = 0xFF, 0xFF, 0xFF |
||
| 428 | themeNone = 0xC0, 0xC0, 0xC0 |
||
| 429 | themeDisabled = 0x80, 0x80, 0x80 |
||
| 430 | |||
| 431 | |||
| 432 | def getDRect(rect): |
||
| 433 | rect = pygame.Rect(rect) |
||
| 434 | rect.left += 1 |
||
| 435 | rect.top += 0 |
||
| 436 | rect.width -= 3 |
||
| 437 | rect.height -= 2 |
||
| 438 | return rect |
||
| 439 | |||
| 440 | def drawArrowButton(surface, widget): |
||
| 441 | if not widget.enabled: |
||
| 442 | s2 = "disabled" |
||
| 443 | elif widget.focused: |
||
| 444 | s2 = "focused" |
||
| 445 | else: |
||
| 446 | s2 = "enabled" |
||
| 447 | if widget.pressed: |
||
| 448 | s3 = "down" |
||
| 449 | else: |
||
| 450 | s3 = "up" |
||
| 451 | if widget.toggle: |
||
| 452 | style = "%s-%s-%s" % (widget.style or "togglebutton", s2, s3) |
||
| 453 | else: |
||
| 454 | style = "%s-%s-%s" % (widget.style or "button", s2, s3) |
||
| 455 | drawBox(surface, widget, style) |
||
| 456 | # arrow |
||
| 457 | fg = boxes[style].foreground or widget.foreground or themeForeground |
||
| 458 | r = getDRect(widget.rect) |
||
| 459 | r.left += 3 |
||
| 460 | r.top += 3 |
||
| 461 | r.width -= 6 |
||
| 462 | r.height -= 6 |
||
| 463 | if widget.direction == Const.ALIGN_N: |
||
| 464 | points = (r.midtop, r.bottomright, r.bottomleft) |
||
| 465 | elif widget.direction == Const.ALIGN_S: |
||
| 466 | points = (r.midbottom, r.topleft, r.topright) |
||
| 467 | elif widget.direction == Const.ALIGN_E: |
||
| 468 | points = (r.midright, r.topleft, r.bottomleft) |
||
| 469 | elif widget.direction == Const.ALIGN_W: |
||
| 470 | points = (r.midleft, r.topright, r.bottomright) |
||
| 471 | pygame.draw.lines(surface, fg, 1, points) |
||
| 472 | return widget.rect |
||
| 473 | |||
| 474 | View Code Duplication | def drawTitleButton(surface, widget): |
|
| 475 | rect = getDRect(widget.rect) |
||
| 476 | rect.height += 1 |
||
| 477 | rect.width += 1 |
||
| 478 | oldClip = surface.get_clip() |
||
| 479 | surface.set_clip(rect) |
||
| 480 | foreground = widget.foreground or themeForeground |
||
| 481 | font = widget.font or themeBoldFont |
||
| 482 | # nicer background |
||
| 483 | surface.fill(themeTitleLine1, rect) |
||
| 484 | x1 = rect.left |
||
| 485 | x2 = rect.right |
||
| 486 | for y in xrange(rect.top, rect.bottom, 2): |
||
| 487 | pygame.draw.line(surface, themeTitleLine2, (x1, y), (x2, y), 1) |
||
| 488 | # icon |
||
| 489 | if widget.icons: |
||
| 490 | for img, align in widget.icons: |
||
| 491 | r = getDRect(rect) |
||
| 492 | if align & Const.ALIGN_W: r.left += 1 |
||
| 493 | elif align & Const.ALIGN_E: r.left += rect.width - img.get_width() |
||
| 494 | else: r.left += (rect.width - img.get_width()) / 2 |
||
| 495 | if align & Const.ALIGN_N: r.top += 1 |
||
| 496 | elif align & Const.ALIGN_S: r.top += rect.height - img.get_height() |
||
| 497 | else: r.top += (rect.height - img.get_height()) / 2 |
||
| 498 | surface.blit(img, r) |
||
| 499 | # text |
||
| 500 | if widget.text != None: |
||
| 501 | if widget.pressed: |
||
| 502 | foreground = themeHighlightfrg |
||
| 503 | img = Fonts.renderText(font, widget.text, 1, foreground) |
||
| 504 | r = getDRect(rect) |
||
| 505 | if widget.align & Const.ALIGN_W: r.left += 2 |
||
| 506 | elif widget.align & Const.ALIGN_E: r.left += rect.width - img.get_width() - 1 |
||
| 507 | else: r.left += (rect.width - img.get_width()) / 2 |
||
| 508 | if widget.align & Const.ALIGN_N: r.top += 2 |
||
| 509 | elif widget.align & Const.ALIGN_S: r.top += rect.height - img.get_height() - 1 |
||
| 510 | else: r.top += (rect.height - img.get_height()) / 2 |
||
| 511 | surface.blit(img, r) |
||
| 512 | surface.set_clip(oldClip) |
||
| 513 | |||
| 514 | View Code Duplication | def drawTitle(surface, widget): |
|
| 515 | rect = getDRect(widget.rect) |
||
| 516 | rect.height += 1 |
||
| 517 | rect.width += 1 |
||
| 518 | oldClip = surface.get_clip() |
||
| 519 | surface.set_clip(rect) |
||
| 520 | foreground = widget.foreground or themeForeground |
||
| 521 | font = widget.font or themeDefaultFont |
||
| 522 | # nicer background |
||
| 523 | surface.fill(themeTitleLine1, rect) |
||
| 524 | x1 = rect.left |
||
| 525 | x2 = rect.right |
||
| 526 | for y in xrange(rect.top, rect.bottom, 2): |
||
| 527 | pygame.draw.line(surface, themeTitleLine2, (x1, y), (x2, y), 1) |
||
| 528 | # icon |
||
| 529 | if widget.icons: |
||
| 530 | for img, align in widget.icons: |
||
| 531 | r = getDRect(rect) |
||
| 532 | if align & Const.ALIGN_W: r.left += 1 |
||
| 533 | elif align & Const.ALIGN_E: r.left += rect.width - img.get_width() |
||
| 534 | else: r.left += (rect.width - img.get_width()) / 2 |
||
| 535 | if align & Const.ALIGN_N: r.top += 1 |
||
| 536 | elif align & Const.ALIGN_S: r.top += rect.height - img.get_height() |
||
| 537 | else: r.top += (rect.height - img.get_height()) / 2 |
||
| 538 | surface.blit(img, r) |
||
| 539 | # text |
||
| 540 | if widget.text != None: |
||
| 541 | img = Fonts.renderText(font, widget.text, 1, foreground) |
||
| 542 | r = getDRect(rect) |
||
| 543 | if widget.align & Const.ALIGN_W: r.left += 2 |
||
| 544 | elif widget.align & Const.ALIGN_E: r.left += rect.width - img.get_width() - 1 |
||
| 545 | else: r.left += (rect.width - img.get_width()) / 2 |
||
| 546 | if widget.align & Const.ALIGN_N: r.top += 2 |
||
| 547 | elif widget.align & Const.ALIGN_S: r.top += rect.height - img.get_height() - 1 |
||
| 548 | else: r.top += (rect.height - img.get_height()) / 2 |
||
| 549 | surface.blit(img, r) |
||
| 550 | surface.set_clip(oldClip) |
||
| 551 | |||
| 552 | def drawEntry(surface, widget): |
||
| 553 | rect = getDRect(widget.rect) |
||
| 554 | oldClip = surface.get_clip() |
||
| 555 | drawBox(surface, widget, "entry-enabled") |
||
| 556 | surface.set_clip(rect) |
||
| 557 | foreground = widget.foreground or themeForeground |
||
| 558 | font = widget.font or themeDefaultFont |
||
| 559 | # text |
||
| 560 | if widget.showChar and widget.text: |
||
| 561 | text = widget.showChar * len(widget.text) |
||
| 562 | else: |
||
| 563 | text = widget.text |
||
| 564 | |||
| 565 | if text: |
||
| 566 | textToCursor = text[:widget.cursorPos] |
||
| 567 | else: |
||
| 568 | textToCursor = '' |
||
| 569 | |||
| 570 | textSize = Fonts.getTextSize(font, text) |
||
| 571 | |||
| 572 | r = getDRect(rect) |
||
| 573 | |||
| 574 | # rendered text is longer than we can display |
||
| 575 | if textSize[0] > r.width: |
||
| 576 | text2 = textToCursor |
||
| 577 | textToIdx = widget.cursorPos |
||
| 578 | textFromIdx = 0 |
||
| 579 | text2Size = Fonts.getTextSize(font, text2) |
||
| 580 | |||
| 581 | if text2Size[0] > r.width: |
||
| 582 | # if text to cursor is longer then width |
||
| 583 | # then delete some chars |
||
| 584 | while text2Size[0] > r.width: |
||
| 585 | text2 = text[textFromIdx:textToIdx] |
||
| 586 | textFromIdx += 1 |
||
| 587 | text2Size = Fonts.getTextSize(font, text2) |
||
| 588 | else: |
||
| 589 | # if text to cursor is shorter then width |
||
| 590 | # then add some chars |
||
| 591 | while text2Size[0] < r.width: |
||
| 592 | text2 = text[textFromIdx:textToIdx] |
||
| 593 | textToIdx += 1 |
||
| 594 | text2Size = Fonts.getTextSize(font, text2) |
||
| 595 | |||
| 596 | text = text2 |
||
| 597 | |||
| 598 | img = Fonts.renderText(font, text, 1, foreground) |
||
| 599 | |||
| 600 | if widget.align & Const.ALIGN_E: |
||
| 601 | r.left += rect.width - img.get_width() - 2 |
||
| 602 | elif not widget.align & Const.ALIGN_W: |
||
| 603 | r.left += (rect.width - img.get_width()) / 2 |
||
| 604 | |||
| 605 | if widget.align & Const.ALIGN_N: |
||
| 606 | r.top += 2 |
||
| 607 | elif widget.align & Const.ALIGN_S: |
||
| 608 | r.top += rect.height - img.get_height() - 1 |
||
| 609 | else: |
||
| 610 | r.top += (rect.height - img.get_height()) / 2 |
||
| 611 | |||
| 612 | surface.blit(img, r) |
||
| 613 | |||
| 614 | if widget.focused and widget.app.cursorOn: |
||
| 615 | offset = Fonts.getTextSize(font, textToCursor) |
||
| 616 | if offset[0] < r.width: |
||
| 617 | # draw cursor in middle of displayed text |
||
| 618 | r.move_ip(offset[0], 0) |
||
| 619 | else: |
||
| 620 | # draw cursor at end of drawed surface |
||
| 621 | r.left += img.get_width() |
||
| 622 | pygame.draw.line(surface, foreground, r.topleft, r.bottomleft, 1) |
||
| 623 | |||
| 624 | surface.set_clip(oldClip) |
||
| 625 | |||
| 626 | def drawDecoratedWindow(surface, window): |
||
| 627 | surface.fill(themeBackground) |
||
| 628 | wa = surface.get_clip() |
||
| 629 | # title |
||
| 630 | if window.title: |
||
| 631 | font = window.font or 'large-bold' |
||
| 632 | if window.focused: |
||
| 633 | color = themeForeground |
||
| 634 | else: |
||
| 635 | color = themeBackground |
||
| 636 | text = Fonts.renderText(font, window.title, 1, color) |
||
| 637 | r = surface.get_clip() |
||
| 638 | r.height = getGridParams()[1] |
||
| 639 | # nicer background |
||
| 640 | surface.fill(themeTitleLine1, r) |
||
| 641 | if window.focused: |
||
| 642 | x1 = r.left |
||
| 643 | x2 = r.right |
||
| 644 | for y in xrange(r.top, r.bottom, 2): |
||
| 645 | pygame.draw.line(surface, themeTitleLine2, (x1, y), (x2, y), 1) |
||
| 646 | r.move_ip(3, (r.height - text.get_height()) / 2) |
||
| 647 | surface.blit(text, r) |
||
| 648 | wa.top += r.height |
||
| 649 | wa.height -= r.height |
||
| 650 | # lines around the window |
||
| 651 | if not window.titleOnly: |
||
| 652 | r = surface.get_clip() |
||
| 653 | r.width -= 1 |
||
| 654 | r.height -= 1 |
||
| 655 | pygame.draw.lines(surface, themeTitleLine1, 1, |
||
| 656 | (r.topleft, r.topright, r.bottomright, r.bottomleft)) |
||
| 657 | r.top += 1 |
||
| 658 | r.left += 1 |
||
| 659 | r.width -= 2 |
||
| 660 | r.height -= 2 |
||
| 661 | pygame.draw.lines(surface, themeTitleLine2, 1, |
||
| 662 | (r.topleft, r.topright, r.bottomright, r.bottomleft)) |
||
| 663 | wa.top += 2 |
||
| 664 | wa.height -= 3 |
||
| 665 | wa.left += 2 |
||
| 666 | wa.width -= 3 |
||
| 667 | return wa |
||
| 668 | |||
| 669 | def drawPlainWindow(surface, window): |
||
| 670 | surface.fill(themeBackground) |
||
| 671 | return surface.get_clip() |
||
| 672 | |||
| 673 | def drawScrollSlider(surface, widget): |
||
| 674 | foreground = widget.foreground or themeForeground |
||
| 675 | r = getDRect(widget.rect) |
||
| 676 | r.left -= 1 |
||
| 677 | r.width += 1 |
||
| 678 | # draw frame |
||
| 679 | surface.fill(themeBackground, r) |
||
| 680 | pygame.draw.lines(surface, themeHighlightbck, 1, |
||
| 681 | (r.topleft, r.topright, r.bottomright, r.bottomleft)) |
||
| 682 | |||
| 683 | # size of slider |
||
| 684 | r.top += 2 |
||
| 685 | r.left += 2 |
||
| 686 | r.height -= 3 |
||
| 687 | r.width -= 3 |
||
| 688 | if r.width > r.height: |
||
| 689 | # horizontal slider |
||
| 690 | # number of items |
||
| 691 | width = widget.max - widget.min |
||
| 692 | # proportional size of slider |
||
| 693 | slider = widget.shown * r.width / width |
||
| 694 | trunc = 0 |
||
| 695 | if slider < themeSliderMin: |
||
| 696 | # slider has lesser size then minimal size for slider |
||
| 697 | # so we store difference between minimal slider size |
||
| 698 | # and size, which should slider have |
||
| 699 | trunc = themeSliderMin - slider |
||
| 700 | # set minimal slider size |
||
| 701 | slider = themeSliderMin |
||
| 702 | if slider > r.width: |
||
| 703 | # if slider is longer then drawing area, cut it |
||
| 704 | slider = r.width |
||
| 705 | |||
| 706 | # compute drawing position withing slider |
||
| 707 | pos = (widget.position - widget.min) * (r.width - trunc) / width |
||
| 708 | |||
| 709 | # set drawing area width to slider size |
||
| 710 | r.width = slider |
||
| 711 | # move draving area to slider position |
||
| 712 | r.left += pos |
||
| 713 | else: |
||
| 714 | # vertical slider |
||
| 715 | # number of items |
||
| 716 | height = widget.max - widget.min |
||
| 717 | # proportional size of slider |
||
| 718 | slider = widget.shown * r.height / height |
||
| 719 | trunc = 0 |
||
| 720 | if slider < themeSliderMin: |
||
| 721 | # slider has lesser size then minimal size for slider |
||
| 722 | # so we store difference between minimal slider size |
||
| 723 | # and size, which should slider have |
||
| 724 | trunc = themeSliderMin - slider |
||
| 725 | # set minimal slider size |
||
| 726 | slider = themeSliderMin |
||
| 727 | if slider > r.height: |
||
| 728 | # if slider is longer then drawing area, cut it |
||
| 729 | slider = r.height |
||
| 730 | |||
| 731 | # compute drawing position withing slider |
||
| 732 | pos = (widget.position - widget.min) * (r.height - trunc) / height |
||
| 733 | |||
| 734 | # set drawing area height to slider size |
||
| 735 | r.height = slider |
||
| 736 | # move draving area to slider position |
||
| 737 | r.top += pos |
||
| 738 | |||
| 739 | # draw slider |
||
| 740 | surface.fill(themeHighlightbck, r) |
||
| 741 | |||
| 742 | if widget.dragging: |
||
| 743 | # slider is dragged by mouse |
||
| 744 | # we are drawing lines, so we must shorten width and height |
||
| 745 | # of slider drawing area to be 'inside' rectangle |
||
| 746 | r.width -= 1 |
||
| 747 | r.height -= 1 |
||
| 748 | # draw lines around slider |
||
| 749 | pygame.draw.lines(surface, themeHighlightfrg, 1, |
||
| 750 | (r.topleft, r.topright, r.bottomright, r.bottomleft)) |
||
| 751 | |||
| 752 | # shorten drawing area one pixel inside |
||
| 753 | r.left += 1 |
||
| 754 | r.top += 1 |
||
| 755 | r.width -= 2 # one pixel from left and one from right |
||
| 756 | r.height -= 2 # one pixel from top and one from bottom |
||
| 757 | # draw lines inside slider |
||
| 758 | pygame.draw.lines(surface, foreground, 1, |
||
| 759 | (r.topleft, r.topright, r.bottomright, r.bottomleft)) |
||
| 760 | else: |
||
| 761 | pass |
||
| 762 | |||
| 763 | # return last drawing area |
||
| 764 | return r |
||
| 765 | |||
| 766 | def drawTooltip(surface, widget): |
||
| 767 | # position rectangle is used only for fetching position |
||
| 768 | pos_r = getDRect(widget.rect) |
||
| 769 | |||
| 770 | # to know what we are dealing with, we have to render all the text first |
||
| 771 | foreground = widget.foreground or themeForeground |
||
| 772 | title_font = widget.font or "small" |
||
| 773 | body_font = widget.font or themeDefaultFont |
||
| 774 | if not body_font.endswith('-italic'): |
||
| 775 | body_font = body_font + "-italic" |
||
| 776 | |||
| 777 | if widget.title: |
||
| 778 | title_img = Fonts.renderText(title_font, widget.title, 1, foreground) |
||
| 779 | title_width = title_img.get_width() |
||
| 780 | title_height = title_img.get_height() |
||
| 781 | max_width = title_width |
||
| 782 | max_height = title_height |
||
| 783 | else: |
||
| 784 | max_width = 0 |
||
| 785 | max_height = 0 |
||
| 786 | |||
| 787 | text_images = [] |
||
| 788 | if widget.text: |
||
| 789 | for line in string.split(widget.text, '\n'): |
||
| 790 | line_img = Fonts.renderText(body_font, line, 1, foreground) |
||
| 791 | text_images += [line_img] |
||
| 792 | max_height += line_img.get_height() |
||
| 793 | max_width = max(max_width, line_img.get_width()) |
||
| 794 | |||
| 795 | # now we have to decide how to fit the tooltip fully into the window |
||
| 796 | screen_width, screen_height = pygame.display.get_surface().get_size() |
||
| 797 | envelope = 8 # so we don't overflow the screen |
||
| 798 | pos_r.left += 20 |
||
| 799 | if pos_r.left + max_width > screen_width: |
||
| 800 | pos_r.left = max(0, screen_width - max_width - envelope) |
||
| 801 | if pos_r.top + max_height > screen_height: |
||
| 802 | pos_r.top = max(0, screen_height - max_height - envelope) |
||
| 803 | |||
| 804 | # title |
||
| 805 | title_r = getDRect(pos_r) |
||
| 806 | title_text_r = getDRect(title_r) |
||
| 807 | if widget.title: |
||
| 808 | title_text_r.width = title_width |
||
| 809 | title_text_r.height = title_height |
||
| 810 | # making 2 pixel free space around text |
||
| 811 | title_text_r.top += 2 |
||
| 812 | title_text_r.left += 2 |
||
| 813 | title_r.width = title_text_r.width + 4 |
||
| 814 | title_r.height = title_text_r.height + 4 |
||
| 815 | else: |
||
| 816 | # have to zero the widget |
||
| 817 | title_r.width = 0 |
||
| 818 | title_r.height = 0 |
||
| 819 | |||
| 820 | # body tooltip |
||
| 821 | body_r = getDRect(pos_r) |
||
| 822 | if widget.text: |
||
| 823 | body_r.top += title_r.height |
||
| 824 | body_text_r = getDRect(body_r) |
||
| 825 | body_height = 0 |
||
| 826 | body_width = 0 |
||
| 827 | for line_img in text_images: |
||
| 828 | body_height += line_img.get_height() |
||
| 829 | body_width = max(body_width, line_img.get_width()) |
||
| 830 | body_text_r.height = body_height |
||
| 831 | body_text_r.width = body_width |
||
| 832 | # making 2 pixel free space around text |
||
| 833 | body_text_r.top += 2 |
||
| 834 | body_text_r.left += 2 |
||
| 835 | body_r.width = body_text_r.width + 4 |
||
| 836 | body_r.height = body_text_r.height + 4 |
||
| 837 | |||
| 838 | # let's draw! |
||
| 839 | # title |
||
| 840 | if widget.title: |
||
| 841 | surface.fill(themeBackground, title_r) |
||
| 842 | pygame.draw.lines(surface, themeForeground, 0, |
||
| 843 | (title_r.bottomleft, title_r.topleft, title_r.topright, title_r.bottomright)) |
||
| 844 | surface.blit(title_img, title_text_r) |
||
| 845 | |||
| 846 | # body |
||
| 847 | if text_images: |
||
| 848 | surface.fill(themeBackground, body_r) |
||
| 849 | pygame.draw.lines(surface, themeForeground, 0, |
||
| 850 | (body_r.topright, body_r.bottomright, body_r.bottomleft, body_r.topleft)) |
||
| 851 | for img in text_images: |
||
| 852 | surface.blit(img, body_text_r) |
||
| 853 | body_text_r.top += img.get_height() |
||
| 854 | body_text_r.height -= img.get_height() |
||
| 855 | |||
| 856 | # finishing touches |
||
| 857 | if text_images and widget.title: |
||
| 858 | pygame.draw.line(surface, themeForeground, body_r.topright, title_r.bottomright) |
||
| 859 | elif widget.title: |
||
| 860 | # closing bottom of title |
||
| 861 | pygame.draw.line(surface, themeForeground, title_r.bottomleft, title_r.bottomright) |
||
| 862 | elif text_images: |
||
| 863 | # closing top of body |
||
| 864 | pygame.draw.line(surface, themeForeground, body_r.topleft, body_r.topright) |
||
| 865 | |||
| 866 | |||
| 867 | # there is probably bug in pygameui, having one pixel off evaluation of rects |
||
| 868 | title_r.height += 1 |
||
| 869 | title_r.width += 1 |
||
| 870 | body_r.width += 1 |
||
| 871 | body_r.height += 1 |
||
| 872 | |||
| 873 | return title_r, body_r |
||
| 874 | |||
| 875 | def drawScrollbar(surface, widget): |
||
| 876 | r = pygame.Rect(widget.rect) |
||
| 877 | surface.fill(themeBackground, r) |
||
| 878 | return r |
||
| 879 | |||
| 880 | def drawListbox(surface, widget): |
||
| 881 | r = pygame.Rect(widget.rect) |
||
| 882 | surface.fill(widget.background or themeBackground, r) |
||
| 883 | return r |
||
| 884 | |||
| 885 | def drawCursor(surface, pos): |
||
| 886 | surface.fill((0xff, 0xff, 0xff), (pos, (2, 2))) |
||
| 887 | |||
| 888 | def drawProgressBar(surface, widget): |
||
| 889 | foreground = widget.foreground or themeForeground |
||
| 890 | r = getDRect(widget.rect) |
||
| 891 | # frame |
||
| 892 | surface.fill(themeBackground, r) |
||
| 893 | pygame.draw.lines(surface, themeHighlightbck, 1, |
||
| 894 | (r.topleft, r.topright, r.bottomright, r.bottomleft)) |
||
| 895 | r.top += 2 |
||
| 896 | r.left += 2 |
||
| 897 | r.height -= 3 |
||
| 898 | r.width -= 3 |
||
| 899 | perc = float(widget.value - widget.min) / (widget.max - widget.min) |
||
| 900 | if r.width > r.height: |
||
| 901 | # horizontal |
||
| 902 | r.width = int(r.width * perc) |
||
| 903 | else: |
||
| 904 | # vertical |
||
| 905 | r.top = r.bottom - int(r.height * perc) |
||
| 906 | surface.fill(themeHighlightbck, r) |
||
| 907 | |||
| 908 | def getTextDrawLines(widget): |
||
| 909 | r = getDRect(widget.rect) |
||
| 910 | img = Fonts.renderText(widget.font or 'normal', ' ', 1, widget.foreground or themeForeground) |
||
| 911 | return r.height / img.get_height() |
||
| 912 | |||
| 913 | def isTextBeyondEnd(widget, text): |
||
| 914 | r = getDRect(widget.rect) |
||
| 915 | size = Fonts.getTextSize(widget.font or 'normal', text) |
||
| 916 | return size[0] >= r.right |
||
| 917 | |||
| 918 | def drawText(surface, widget): |
||
| 919 | oldClip = surface.get_clip() |
||
| 920 | surface.set_clip(widget.rect) |
||
| 921 | fore = foreground = widget.foreground or themeForeground |
||
| 922 | back = background = widget.background or themeBackground |
||
| 923 | font = widget.font or 'normal' |
||
| 924 | r = getDRect(widget.rect) |
||
| 925 | drawBox(surface, widget, "entry-enabled") |
||
| 926 | line = 0 |
||
| 927 | x = r.left |
||
| 928 | y = r.top |
||
| 929 | img = Fonts.renderText(font, ' ', 1, foreground) |
||
| 930 | row = 0 |
||
| 931 | for para in widget.text: |
||
| 932 | if row < widget.offsetRow: |
||
| 933 | row += 1 |
||
| 934 | continue |
||
| 935 | onlyword = False |
||
| 936 | column = 0 |
||
| 937 | charIdx = 0 |
||
| 938 | firstY = y |
||
| 939 | previous_width = 0 |
||
| 940 | for char in para: |
||
| 941 | fore = foreground |
||
| 942 | back = None |
||
| 943 | if widget.selection and widget.selection.first <= (row, column) < widget.selection.last: |
||
| 944 | # switch colors for foreground/background |
||
| 945 | fore = background |
||
| 946 | back = foreground |
||
| 947 | |||
| 948 | # simple hack to add word wrapping |
||
| 949 | # get words from the current char to end of paragraph |
||
| 950 | words = para[charIdx:].split(' ') |
||
| 951 | # compute length of rendered first word |
||
| 952 | remainingWordSize = Fonts.getTextSize(font, words[0]) |
||
| 953 | # if word doesn't fit to current line, |
||
| 954 | # move to next line |
||
| 955 | if x + remainingWordSize[0] + 10 > r.right: |
||
| 956 | if x == (r.left + previous_width) or onlyword: # only word on line, and still too large! Render as much as we can, then move to next line. |
||
| 957 | onlyword = True |
||
| 958 | if x + 10 > r.right: |
||
| 959 | if not r.left + remainingWordSize[0] + 10 > r.right: # finally, end of word |
||
| 960 | onlyword = False |
||
| 961 | x = r.left; |
||
| 962 | y += remainingWordSize[1] |
||
| 963 | if y + img.get_height() > r.bottom: |
||
| 964 | surface.set_clip(oldClip) |
||
| 965 | return |
||
| 966 | else: |
||
| 967 | x = r.left; |
||
| 968 | y += remainingWordSize[1] |
||
| 969 | if y + img.get_height() > r.bottom: |
||
| 970 | surface.set_clip(oldClip) |
||
| 971 | return |
||
| 972 | # render next char |
||
| 973 | img = Fonts.renderText(font, char, 1, fore, back) |
||
| 974 | # compute next char position |
||
| 975 | previous_width = img.get_width() |
||
| 976 | newX = x + previous_width |
||
| 977 | |||
| 978 | surface.blit(img, (x, y)) |
||
| 979 | column += 1 |
||
| 980 | charIdx += 1 |
||
| 981 | |||
| 982 | if widget.editable and row == widget.cursorRow and \ |
||
| 983 | widget.focused and widget.app.cursorOn and \ |
||
| 984 | column == widget.cursorColumn: |
||
| 985 | pygame.draw.line(surface, foreground, (newX, y), (newX, y + img.get_height()), 1) |
||
| 986 | |||
| 987 | x = newX |
||
| 988 | |||
| 989 | # draw cursor in case of zero length paragraph or begining of line |
||
| 990 | if (len(para) == 0 or widget.cursorColumn == 0) and \ |
||
| 991 | widget.editable and row == widget.cursorRow and \ |
||
| 992 | widget.focused and widget.app.cursorOn: |
||
| 993 | pygame.draw.line(surface, foreground, (r.left, firstY), (r.left, firstY + img.get_height()), 1) |
||
| 994 | |||
| 995 | x = r.left |
||
| 996 | y += img.get_height() |
||
| 997 | row += 1 |
||
| 998 | line += 1 |
||
| 999 | if y + img.get_height() > r.bottom: |
||
| 1000 | surface.set_clip(oldClip) |
||
| 1001 | return |
||
| 1002 | surface.set_clip(oldClip) |
||
| 1003 |