Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: third_party/twisted_8_1/twisted/conch/insults/window.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.conch.test.test_window -*-
2
3 """
4 Simple insults-based widget library
5
6 @author: U{Jp Calderone<mailto:exarkun@twistedmatrix.com>}
7 """
8
9 import array
10
11 from twisted.conch.insults import insults, helper
12 from twisted.python import text as tptext
13
14 class YieldFocus(Exception):
15 """Input focus manipulation exception
16 """
17
18 class BoundedTerminalWrapper(object):
19 def __init__(self, terminal, width, height, xoff, yoff):
20 self.width = width
21 self.height = height
22 self.xoff = xoff
23 self.yoff = yoff
24 self.terminal = terminal
25 self.cursorForward = terminal.cursorForward
26 self.selectCharacterSet = terminal.selectCharacterSet
27 self.selectGraphicRendition = terminal.selectGraphicRendition
28 self.saveCursor = terminal.saveCursor
29 self.restoreCursor = terminal.restoreCursor
30
31 def cursorPosition(self, x, y):
32 return self.terminal.cursorPosition(
33 self.xoff + min(self.width, x),
34 self.yoff + min(self.height, y)
35 )
36
37 def cursorHome(self):
38 return self.terminal.cursorPosition(
39 self.xoff, self.yoff)
40
41 def write(self, bytes):
42 return self.terminal.write(bytes)
43
44 class Widget(object):
45 focused = False
46 parent = None
47 dirty = False
48 width = height = None
49
50 def repaint(self):
51 if not self.dirty:
52 self.dirty = True
53 if self.parent is not None and not self.parent.dirty:
54 self.parent.repaint()
55
56 def filthy(self):
57 self.dirty = True
58
59 def redraw(self, width, height, terminal):
60 self.filthy()
61 self.draw(width, height, terminal)
62
63 def draw(self, width, height, terminal):
64 if width != self.width or height != self.height or self.dirty:
65 self.width = width
66 self.height = height
67 self.dirty = False
68 self.render(width, height, terminal)
69
70 def render(self, width, height, terminal):
71 pass
72
73 def sizeHint(self):
74 return None
75
76 def keystrokeReceived(self, keyID, modifier):
77 if keyID == '\t':
78 self.tabReceived(modifier)
79 elif keyID == '\x7f':
80 self.backspaceReceived()
81 elif keyID in insults.FUNCTION_KEYS:
82 self.functionKeyReceived(keyID, modifier)
83 else:
84 self.characterReceived(keyID, modifier)
85
86 def tabReceived(self, modifier):
87 # XXX TODO - Handle shift+tab
88 raise YieldFocus()
89
90 def focusReceived(self):
91 """Called when focus is being given to this widget.
92
93 May raise YieldFocus is this widget does not want focus.
94 """
95 self.focused = True
96 self.repaint()
97
98 def focusLost(self):
99 self.focused = False
100 self.repaint()
101
102 def backspaceReceived(self):
103 pass
104
105 def functionKeyReceived(self, keyID, modifier):
106 func = getattr(self, 'func_' + keyID.name, None)
107 if func is not None:
108 func(modifier)
109
110 def characterReceived(self, keyID, modifier):
111 pass
112
113 class ContainerWidget(Widget):
114 """
115 @ivar focusedChild: The contained widget which currently has
116 focus, or None.
117 """
118 focusedChild = None
119 focused = False
120
121 def __init__(self):
122 Widget.__init__(self)
123 self.children = []
124
125 def addChild(self, child):
126 assert child.parent is None
127 child.parent = self
128 self.children.append(child)
129 if self.focusedChild is None and self.focused:
130 try:
131 child.focusReceived()
132 except YieldFocus:
133 pass
134 else:
135 self.focusedChild = child
136 self.repaint()
137
138 def remChild(self, child):
139 assert child.parent is self
140 child.parent = None
141 self.children.remove(child)
142 self.repaint()
143
144 def filthy(self):
145 for ch in self.children:
146 ch.filthy()
147 Widget.filthy(self)
148
149 def render(self, width, height, terminal):
150 for ch in self.children:
151 ch.draw(width, height, terminal)
152
153 def changeFocus(self):
154 self.repaint()
155
156 if self.focusedChild is not None:
157 self.focusedChild.focusLost()
158 focusedChild = self.focusedChild
159 self.focusedChild = None
160 try:
161 curFocus = self.children.index(focusedChild) + 1
162 except ValueError:
163 raise YieldFocus()
164 else:
165 curFocus = 0
166 while curFocus < len(self.children):
167 try:
168 self.children[curFocus].focusReceived()
169 except YieldFocus:
170 curFocus += 1
171 else:
172 self.focusedChild = self.children[curFocus]
173 return
174 # None of our children wanted focus
175 raise YieldFocus()
176
177
178 def focusReceived(self):
179 self.changeFocus()
180 self.focused = True
181
182
183 def keystrokeReceived(self, keyID, modifier):
184 if self.focusedChild is not None:
185 try:
186 self.focusedChild.keystrokeReceived(keyID, modifier)
187 except YieldFocus:
188 self.changeFocus()
189 self.repaint()
190 else:
191 Widget.keystrokeReceived(self, keyID, modifier)
192
193
194 class TopWindow(ContainerWidget):
195 """
196 A top-level container object which provides focus wrap-around and paint
197 scheduling.
198
199 @ivar painter: A no-argument callable which will be invoked when this
200 widget needs to be redrawn.
201
202 @ivar scheduler: A one-argument callable which will be invoked with a
203 no-argument callable and should arrange for it to invoked at some point in
204 the near future. The no-argument callable will cause this widget and all
205 its children to be redrawn. It is typically beneficial for the no-argument
206 callable to be invoked at the end of handling for whatever event is
207 currently active; for example, it might make sense to call it at the end of
208 L{twisted.conch.insults.insults.ITerminalProtocol.keystrokeReceived}.
209 Note, however, that since calls to this may also be made in response to no
210 apparent event, arrangements should be made for the function to be called
211 even if an event handler such as C{keystrokeReceived} is not on the call
212 stack (eg, using C{reactor.callLater} with a short timeout).
213 """
214 focused = True
215
216 def __init__(self, painter, scheduler):
217 ContainerWidget.__init__(self)
218 self.painter = painter
219 self.scheduler = scheduler
220
221 _paintCall = None
222 def repaint(self):
223 if self._paintCall is None:
224 self._paintCall = object()
225 self.scheduler(self._paint)
226 ContainerWidget.repaint(self)
227
228 def _paint(self):
229 self._paintCall = None
230 self.painter()
231
232 def changeFocus(self):
233 try:
234 ContainerWidget.changeFocus(self)
235 except YieldFocus:
236 try:
237 ContainerWidget.changeFocus(self)
238 except YieldFocus:
239 pass
240
241 def keystrokeReceived(self, keyID, modifier):
242 try:
243 ContainerWidget.keystrokeReceived(self, keyID, modifier)
244 except YieldFocus:
245 self.changeFocus()
246
247
248 class AbsoluteBox(ContainerWidget):
249 def moveChild(self, child, x, y):
250 for n in range(len(self.children)):
251 if self.children[n][0] is child:
252 self.children[n] = (child, x, y)
253 break
254 else:
255 raise ValueError("No such child", child)
256
257 def render(self, width, height, terminal):
258 for (ch, x, y) in self.children:
259 wrap = BoundedTerminalWrapper(terminal, width - x, height - y, x, y)
260 ch.draw(width, height, wrap)
261
262
263 class _Box(ContainerWidget):
264 TOP, CENTER, BOTTOM = range(3)
265
266 def __init__(self, gravity=CENTER):
267 ContainerWidget.__init__(self)
268 self.gravity = gravity
269
270 def sizeHint(self):
271 height = 0
272 width = 0
273 for ch in self.children:
274 hint = ch.sizeHint()
275 if hint is None:
276 hint = (None, None)
277
278 if self.variableDimension == 0:
279 if hint[0] is None:
280 width = None
281 elif width is not None:
282 width += hint[0]
283 if hint[1] is None:
284 height = None
285 elif height is not None:
286 height = max(height, hint[1])
287 else:
288 if hint[0] is None:
289 width = None
290 elif width is not None:
291 width = max(width, hint[0])
292 if hint[1] is None:
293 height = None
294 elif height is not None:
295 height += hint[1]
296
297 return width, height
298
299
300 def render(self, width, height, terminal):
301 if not self.children:
302 return
303
304 greedy = 0
305 wants = []
306 for ch in self.children:
307 hint = ch.sizeHint()
308 if hint is None:
309 hint = (None, None)
310 if hint[self.variableDimension] is None:
311 greedy += 1
312 wants.append(hint[self.variableDimension])
313
314 length = (width, height)[self.variableDimension]
315 totalWant = sum([w for w in wants if w is not None])
316 if greedy:
317 leftForGreedy = int((length - totalWant) / greedy)
318
319 widthOffset = heightOffset = 0
320
321 for want, ch in zip(wants, self.children):
322 if want is None:
323 want = leftForGreedy
324
325 subWidth, subHeight = width, height
326 if self.variableDimension == 0:
327 subWidth = want
328 else:
329 subHeight = want
330
331 wrap = BoundedTerminalWrapper(
332 terminal,
333 subWidth,
334 subHeight,
335 widthOffset,
336 heightOffset,
337 )
338 ch.draw(subWidth, subHeight, wrap)
339 if self.variableDimension == 0:
340 widthOffset += want
341 else:
342 heightOffset += want
343
344
345 class HBox(_Box):
346 variableDimension = 0
347
348 class VBox(_Box):
349 variableDimension = 1
350
351
352 class Packer(ContainerWidget):
353 def render(self, width, height, terminal):
354 if not self.children:
355 return
356
357 root = int(len(self.children) ** 0.5 + 0.5)
358 boxes = [VBox() for n in range(root)]
359 for n, ch in enumerate(self.children):
360 boxes[n % len(boxes)].addChild(ch)
361 h = HBox()
362 map(h.addChild, boxes)
363 h.render(width, height, terminal)
364
365
366 class Canvas(Widget):
367 focused = False
368
369 contents = None
370
371 def __init__(self):
372 Widget.__init__(self)
373 self.resize(1, 1)
374
375 def resize(self, width, height):
376 contents = array.array('c', ' ' * width * height)
377 if self.contents is not None:
378 for x in range(min(width, self._width)):
379 for y in range(min(height, self._height)):
380 contents[width * y + x] = self[x, y]
381 self.contents = contents
382 self._width = width
383 self._height = height
384 if self.x >= width:
385 self.x = width - 1
386 if self.y >= height:
387 self.y = height - 1
388
389 def __getitem__(self, (x, y)):
390 return self.contents[(self._width * y) + x]
391
392 def __setitem__(self, (x, y), value):
393 self.contents[(self._width * y) + x] = value
394
395 def clear(self):
396 self.contents = array.array('c', ' ' * len(self.contents))
397
398 def render(self, width, height, terminal):
399 if not width or not height:
400 return
401
402 if width != self._width or height != self._height:
403 self.resize(width, height)
404 for i in range(height):
405 terminal.cursorPosition(0, i)
406 terminal.write(''.join(self.contents[self._width * i:self._width * i + self._width])[:width])
407
408
409 def horizontalLine(terminal, y, left, right):
410 terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0)
411 terminal.cursorPosition(left, y)
412 terminal.write(chr(0161) * (right - left))
413 terminal.selectCharacterSet(insults.CS_US, insults.G0)
414
415 def verticalLine(terminal, x, top, bottom):
416 terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0)
417 for n in xrange(top, bottom):
418 terminal.cursorPosition(x, n)
419 terminal.write(chr(0170))
420 terminal.selectCharacterSet(insults.CS_US, insults.G0)
421
422
423 def rectangle(terminal, (top, left), (width, height)):
424 terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0)
425
426 terminal.cursorPosition(top, left)
427 terminal.write(chr(0154))
428 terminal.write(chr(0161) * (width - 2))
429 terminal.write(chr(0153))
430 for n in range(height - 2):
431 terminal.cursorPosition(left, top + n + 1)
432 terminal.write(chr(0170))
433 terminal.cursorForward(width - 2)
434 terminal.write(chr(0170))
435 terminal.cursorPosition(0, top + height - 1)
436 terminal.write(chr(0155))
437 terminal.write(chr(0161) * (width - 2))
438 terminal.write(chr(0152))
439
440 terminal.selectCharacterSet(insults.CS_US, insults.G0)
441
442 class Border(Widget):
443 def __init__(self, containee):
444 Widget.__init__(self)
445 self.containee = containee
446 self.containee.parent = self
447
448 def focusReceived(self):
449 return self.containee.focusReceived()
450
451 def focusLost(self):
452 return self.containee.focusLost()
453
454 def keystrokeReceived(self, keyID, modifier):
455 return self.containee.keystrokeReceived(keyID, modifier)
456
457 def sizeHint(self):
458 hint = self.containee.sizeHint()
459 if hint is None:
460 hint = (None, None)
461 if hint[0] is None:
462 x = None
463 else:
464 x = hint[0] + 2
465 if hint[1] is None:
466 y = None
467 else:
468 y = hint[1] + 2
469 return x, y
470
471 def filthy(self):
472 self.containee.filthy()
473 Widget.filthy(self)
474
475 def render(self, width, height, terminal):
476 if self.containee.focused:
477 terminal.write('\x1b[31m')
478 rectangle(terminal, (0, 0), (width, height))
479 terminal.write('\x1b[0m')
480 wrap = BoundedTerminalWrapper(terminal, width - 2, height - 2, 1, 1)
481 self.containee.draw(width - 2, height - 2, wrap)
482
483
484 class Button(Widget):
485 def __init__(self, label, onPress):
486 Widget.__init__(self)
487 self.label = label
488 self.onPress = onPress
489
490 def sizeHint(self):
491 return len(self.label), 1
492
493 def characterReceived(self, keyID, modifier):
494 if keyID == '\r':
495 self.onPress()
496
497 def render(self, width, height, terminal):
498 terminal.cursorPosition(0, 0)
499 if self.focused:
500 terminal.write('\x1b[1m' + self.label + '\x1b[0m')
501 else:
502 terminal.write(self.label)
503
504 class TextInput(Widget):
505 def __init__(self, maxwidth, onSubmit):
506 Widget.__init__(self)
507 self.onSubmit = onSubmit
508 self.maxwidth = maxwidth
509 self.buffer = ''
510 self.cursor = 0
511
512 def setText(self, text):
513 self.buffer = text[:self.maxwidth]
514 self.cursor = len(self.buffer)
515 self.repaint()
516
517 def func_LEFT_ARROW(self, modifier):
518 if self.cursor > 0:
519 self.cursor -= 1
520 self.repaint()
521
522 def func_RIGHT_ARROW(self, modifier):
523 if self.cursor < len(self.buffer):
524 self.cursor += 1
525 self.repaint()
526
527 def backspaceReceived(self):
528 if self.cursor > 0:
529 self.buffer = self.buffer[:self.cursor - 1] + self.buffer[self.curso r:]
530 self.cursor -= 1
531 self.repaint()
532
533 def characterReceived(self, keyID, modifier):
534 if keyID == '\r':
535 self.onSubmit(self.buffer)
536 else:
537 if len(self.buffer) < self.maxwidth:
538 self.buffer = self.buffer[:self.cursor] + keyID + self.buffer[se lf.cursor:]
539 self.cursor += 1
540 self.repaint()
541
542 def sizeHint(self):
543 return self.maxwidth + 1, 1
544
545 def render(self, width, height, terminal):
546 currentText = self._renderText()
547 terminal.cursorPosition(0, 0)
548 if self.focused:
549 terminal.write(currentText[:self.cursor])
550 cursor(terminal, currentText[self.cursor:self.cursor+1] or ' ')
551 terminal.write(currentText[self.cursor+1:])
552 terminal.write(' ' * (self.maxwidth - len(currentText) + 1))
553 else:
554 more = self.maxwidth - len(currentText)
555 terminal.write(currentText + '_' * more)
556
557 def _renderText(self):
558 return self.buffer
559
560 class PasswordInput(TextInput):
561 def _renderText(self):
562 return '*' * len(self.buffer)
563
564 class TextOutput(Widget):
565 text = ''
566
567 def __init__(self, size=None):
568 Widget.__init__(self)
569 self.size = size
570
571 def sizeHint(self):
572 return self.size
573
574 def render(self, width, height, terminal):
575 terminal.cursorPosition(0, 0)
576 text = self.text[:width]
577 terminal.write(text + ' ' * (width - len(text)))
578
579 def setText(self, text):
580 self.text = text
581 self.repaint()
582
583 def focusReceived(self):
584 raise YieldFocus()
585
586 class TextOutputArea(TextOutput):
587 WRAP, TRUNCATE = range(2)
588
589 def __init__(self, size=None, longLines=WRAP):
590 TextOutput.__init__(self, size)
591 self.longLines = longLines
592
593 def render(self, width, height, terminal):
594 n = 0
595 inputLines = self.text.splitlines()
596 outputLines = []
597 while inputLines:
598 if self.longLines == self.WRAP:
599 wrappedLines = tptext.greedyWrap(inputLines.pop(0), width)
600 outputLines.extend(wrappedLines or [''])
601 else:
602 outputLines.append(inputLines.pop(0)[:width])
603 if len(outputLines) >= height:
604 break
605 for n, L in enumerate(outputLines[:height]):
606 terminal.cursorPosition(0, n)
607 terminal.write(L)
608
609 class Viewport(Widget):
610 _xOffset = 0
611 _yOffset = 0
612
613 def xOffset():
614 def get(self):
615 return self._xOffset
616 def set(self, value):
617 if self._xOffset != value:
618 self._xOffset = value
619 self.repaint()
620 return get, set
621 xOffset = property(*xOffset())
622
623 def yOffset():
624 def get(self):
625 return self._yOffset
626 def set(self, value):
627 if self._yOffset != value:
628 self._yOffset = value
629 self.repaint()
630 return get, set
631 yOffset = property(*yOffset())
632
633 _width = 160
634 _height = 24
635
636 def __init__(self, containee):
637 Widget.__init__(self)
638 self.containee = containee
639 self.containee.parent = self
640
641 self._buf = helper.TerminalBuffer()
642 self._buf.width = self._width
643 self._buf.height = self._height
644 self._buf.connectionMade()
645
646 def filthy(self):
647 self.containee.filthy()
648 Widget.filthy(self)
649
650 def render(self, width, height, terminal):
651 self.containee.draw(self._width, self._height, self._buf)
652
653 # XXX /Lame/
654 for y, line in enumerate(self._buf.lines[self._yOffset:self._yOffset + h eight]):
655 terminal.cursorPosition(0, y)
656 n = 0
657 for n, (ch, attr) in enumerate(line[self._xOffset:self._xOffset + wi dth]):
658 if ch is self._buf.void:
659 ch = ' '
660 terminal.write(ch)
661 if n < width:
662 terminal.write(' ' * (width - n - 1))
663
664
665 class _Scrollbar(Widget):
666 def __init__(self, onScroll):
667 Widget.__init__(self)
668 self.onScroll = onScroll
669 self.percent = 0.0
670
671 def smaller(self):
672 self.percent = min(1.0, max(0.0, self.onScroll(-1)))
673 self.repaint()
674
675 def bigger(self):
676 self.percent = min(1.0, max(0.0, self.onScroll(+1)))
677 self.repaint()
678
679
680 class HorizontalScrollbar(_Scrollbar):
681 def sizeHint(self):
682 return (None, 1)
683
684 def func_LEFT_ARROW(self, modifier):
685 self.smaller()
686
687 def func_RIGHT_ARROW(self, modifier):
688 self.bigger()
689
690 _left = u'\N{BLACK LEFT-POINTING TRIANGLE}'
691 _right = u'\N{BLACK RIGHT-POINTING TRIANGLE}'
692 _bar = u'\N{LIGHT SHADE}'
693 _slider = u'\N{DARK SHADE}'
694 def render(self, width, height, terminal):
695 terminal.cursorPosition(0, 0)
696 n = width - 3
697 before = int(n * self.percent)
698 after = n - before
699 me = self._left + (self._bar * before) + self._slider + (self._bar * aft er) + self._right
700 terminal.write(me.encode('utf-8'))
701
702
703 class VerticalScrollbar(_Scrollbar):
704 def sizeHint(self):
705 return (1, None)
706
707 def func_UP_ARROW(self, modifier):
708 self.smaller()
709
710 def func_DOWN_ARROW(self, modifier):
711 self.bigger()
712
713 _up = u'\N{BLACK UP-POINTING TRIANGLE}'
714 _down = u'\N{BLACK DOWN-POINTING TRIANGLE}'
715 _bar = u'\N{LIGHT SHADE}'
716 _slider = u'\N{DARK SHADE}'
717 def render(self, width, height, terminal):
718 terminal.cursorPosition(0, 0)
719 knob = int(self.percent * (height - 2))
720 terminal.write(self._up.encode('utf-8'))
721 for i in xrange(1, height - 1):
722 terminal.cursorPosition(0, i)
723 if i != (knob + 1):
724 terminal.write(self._bar.encode('utf-8'))
725 else:
726 terminal.write(self._slider.encode('utf-8'))
727 terminal.cursorPosition(0, height - 1)
728 terminal.write(self._down.encode('utf-8'))
729
730
731 class ScrolledArea(Widget):
732 def __init__(self, containee):
733 Widget.__init__(self, containee)
734 self._viewport = Viewport(containee)
735 self._horiz = HorizontalScrollbar(self._horizScroll)
736 self._vert = VerticalScrollbar(self._vertScroll)
737
738 for w in self._viewport, self._horiz, self._vert:
739 w.parent = self
740
741 def _horizScroll(self, n):
742 self._viewport.xOffset += n
743 self._viewport.xOffset = max(0, self._viewport.xOffset)
744 return self._viewport.xOffset / 25.0
745
746 def _vertScroll(self, n):
747 self._viewport.yOffset += n
748 self._viewport.yOffset = max(0, self._viewport.yOffset)
749 return self._viewport.yOffset / 25.0
750
751 def func_UP_ARROW(self, modifier):
752 self._vert.smaller()
753
754 def func_DOWN_ARROW(self, modifier):
755 self._vert.bigger()
756
757 def func_LEFT_ARROW(self, modifier):
758 self._horiz.smaller()
759
760 def func_RIGHT_ARROW(self, modifier):
761 self._horiz.bigger()
762
763 def filthy(self):
764 self._viewport.filthy()
765 self._horiz.filthy()
766 self._vert.filthy()
767 Widget.filthy(self)
768
769 def render(self, width, height, terminal):
770 wrapper = BoundedTerminalWrapper(terminal, width - 2, height - 2, 1, 1)
771 self._viewport.draw(width - 2, height - 2, wrapper)
772 if self.focused:
773 terminal.write('\x1b[31m')
774 horizontalLine(terminal, 0, 1, width - 1)
775 verticalLine(terminal, 0, 1, height - 1)
776 self._vert.draw(1, height - 1, BoundedTerminalWrapper(terminal, 1, heigh t - 1, width - 1, 0))
777 self._horiz.draw(width, 1, BoundedTerminalWrapper(terminal, width, 1, 0, height - 1))
778 terminal.write('\x1b[0m')
779
780 def cursor(terminal, ch):
781 terminal.saveCursor()
782 terminal.selectGraphicRendition(str(insults.REVERSE_VIDEO))
783 terminal.write(ch)
784 terminal.restoreCursor()
785 terminal.cursorForward()
786
787 class Selection(Widget):
788 # Index into the sequence
789 focusedIndex = 0
790
791 # Offset into the displayed subset of the sequence
792 renderOffset = 0
793
794 def __init__(self, sequence, onSelect, minVisible=None):
795 Widget.__init__(self)
796 self.sequence = sequence
797 self.onSelect = onSelect
798 self.minVisible = minVisible
799 if minVisible is not None:
800 self._width = max(map(len, self.sequence))
801
802 def sizeHint(self):
803 if self.minVisible is not None:
804 return self._width, self.minVisible
805
806 def func_UP_ARROW(self, modifier):
807 if self.focusedIndex > 0:
808 self.focusedIndex -= 1
809 if self.renderOffset > 0:
810 self.renderOffset -= 1
811 self.repaint()
812
813 def func_PGUP(self, modifier):
814 if self.renderOffset != 0:
815 self.focusedIndex -= self.renderOffset
816 self.renderOffset = 0
817 else:
818 self.focusedIndex = max(0, self.focusedIndex - self.height)
819 self.repaint()
820
821 def func_DOWN_ARROW(self, modifier):
822 if self.focusedIndex < len(self.sequence) - 1:
823 self.focusedIndex += 1
824 if self.renderOffset < self.height - 1:
825 self.renderOffset += 1
826 self.repaint()
827
828
829 def func_PGDN(self, modifier):
830 if self.renderOffset != self.height - 1:
831 change = self.height - self.renderOffset - 1
832 if change + self.focusedIndex >= len(self.sequence):
833 change = len(self.sequence) - self.focusedIndex - 1
834 self.focusedIndex += change
835 self.renderOffset = self.height - 1
836 else:
837 self.focusedIndex = min(len(self.sequence) - 1, self.focusedIndex + self.height)
838 self.repaint()
839
840 def characterReceived(self, keyID, modifier):
841 if keyID == '\r':
842 self.onSelect(self.sequence[self.focusedIndex])
843
844 def render(self, width, height, terminal):
845 self.height = height
846 start = self.focusedIndex - self.renderOffset
847 if start > len(self.sequence) - height:
848 start = max(0, len(self.sequence) - height)
849
850 elements = self.sequence[start:start+height]
851
852 for n, ele in enumerate(elements):
853 terminal.cursorPosition(0, n)
854 if n == self.renderOffset:
855 terminal.saveCursor()
856 if self.focused:
857 modes = str(insults.REVERSE_VIDEO), str(insults.BOLD)
858 else:
859 modes = str(insults.REVERSE_VIDEO),
860 terminal.selectGraphicRendition(*modes)
861 text = ele[:width]
862 terminal.write(text + (' ' * (width - len(text))))
863 if n == self.renderOffset:
864 terminal.restoreCursor()
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/conch/insults/text.py ('k') | third_party/twisted_8_1/twisted/conch/interfaces.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698