tuikit/driver/cursesw.py
changeset 118 8c7970520632
parent 113 6796adfdc7eb
child 119 dd91747504dd
equal deleted inserted replaced
117:8680c2333546 118:8c7970520632
     1 import curses.ascii
     1 import curses.ascii
     2 import math
     2 import math
     3 import logging
     3 import logging
     4 
     4 
     5 from tuikit.driver.driver import Driver
     5 from tuikit.driver.driver import Driver
     6 from tuikit.core.events import ResizeEvent, KeypressEvent
     6 from tuikit.core.events import ResizeEvent, KeypressEvent, MouseEvent
     7 from tuikit.core.coords import Point
     7 from tuikit.core.coords import Point
     8 
     8 
     9 
     9 
    10 class CursesWDriver(Driver):
    10 class CursesWDriver(Driver):
    11 
    11 
   104                 self.stdscr.addch(y, x, ch)
   104                 self.stdscr.addch(y, x, ch)
   105             elif isinstance(ch, str) and len(ch) == 1:
   105             elif isinstance(ch, str) and len(ch) == 1:
   106                 self.stdscr.addstr(y, x, ch)
   106                 self.stdscr.addstr(y, x, ch)
   107             else:
   107             else:
   108                 raise TypeError('Integer or one-char string is required.')
   108                 raise TypeError('Integer or one-char string is required.')
   109         except curses.error as e:
   109         except curses.error:
       
   110             if x == self.size.w - 1 and y == self.size.h - 1:
       
   111                 # Curses putch to lower-right corner gives error because
       
   112                 # scrolling is disabled and cursor cannot move to next char.
       
   113                 # Let's just ignore that for now.
       
   114                 return
   110             self._log.exception('putch(%r, %s, %s) error:' % (ch, x, y))
   115             self._log.exception('putch(%r, %s, %s) error:' % (ch, x, y))
   111 
   116 
   112     def draw(self, buffer, x=0, y=0):
   117     def draw(self, buffer, x=0, y=0):
   113         for bufy in range(buffer.size.h):
   118         for bufy in range(buffer.size.h):
   114             for bufx in range(buffer.size.w):
   119             for bufx in range(buffer.size.w):
   160         """Process input, return list of events.
   165         """Process input, return list of events.
   161 
   166 
   162         timeout -- float, in seconds (None=infinite)
   167         timeout -- float, in seconds (None=infinite)
   163 
   168 
   164         Returns:
   169         Returns:
   165             [('event', param1, ...), ...]
   170             List of Event objects.
   166 
   171 
   167         """
   172         """
   168         # Set timeout
   173         # Set timeout
   169         if timeout is None:
   174         if timeout is None:
   170             # wait indefinitely
   175             # wait indefinitely
   198             res.append(KeypressEvent(keyname, c, set()))
   203             res.append(KeypressEvent(keyname, c, set()))
   199 
   204 
   200         return res
   205         return res
   201 
   206 
   202     def _process_mouse(self):
   207     def _process_mouse(self):
   203         out = []
   208         res = []
   204         try:
   209         try:
   205             _id, x, y, _z, bstate = curses.getmouse()
   210             _id, x, y, _z, bstate = curses.getmouse()
   206         except curses.error:
   211         except curses.error:
   207             return out
   212             return res
   208 
   213 
   209         pos = Point(x, y)
   214         pos = Point(x, y)
   210         if bstate & curses.REPORT_MOUSE_POSITION:
   215         if bstate & curses.REPORT_MOUSE_POSITION:
   211             if self._mouse_last_pos != pos:
   216             if self._mouse_last_pos != pos:
   212                 if self._mouse_last_pos:
   217                 if self._mouse_last_pos:
   213                     relpos = pos - self._mouse_last_pos
   218                     relpos = pos - self._mouse_last_pos
   214                     out += [('mousemove', 0, pos, relpos)]
   219                     res.append(MouseEvent('mousemove', 0, pos, relpos))
   215                 self._mouse_last_pos = pos
   220                 self._mouse_last_pos = pos
   216 
   221 
   217         # we are interested only in changes, not buttons already pressed before event
   222         # We are interested only in changes, not buttons already pressed before event
   218         if self._mouse_last_bstate is not None:
   223         if self._mouse_last_bstate is not None:
   219             old = self._mouse_last_bstate
   224             old = self._mouse_last_bstate
   220             new = bstate
   225             new = bstate
   221             bstate = ~old & new
   226             bstate = ~old & new
   222             self._mouse_last_bstate = new
   227             self._mouse_last_bstate = new
   223         else:
   228         else:
   224             self._mouse_last_bstate = bstate
   229             self._mouse_last_bstate = bstate
   225 
   230 
   226         if bstate & curses.BUTTON1_PRESSED:
   231         if bstate & curses.BUTTON1_PRESSED:
   227             out += [('mousedown', 1, pos)]
   232             res.append(MouseEvent('mousedown', 1, pos))
   228         if bstate & curses.BUTTON2_PRESSED:
   233         if bstate & curses.BUTTON2_PRESSED:
   229             out += [('mousedown', 2, pos)]
   234             res.append(MouseEvent('mousedown', 2, pos))
   230         if bstate & curses.BUTTON3_PRESSED:
   235         if bstate & curses.BUTTON3_PRESSED:
   231             out += [('mousedown', 3, pos)]
   236             res.append(MouseEvent('mousedown', 3, pos))
   232         if bstate & curses.BUTTON1_RELEASED:
   237         if bstate & curses.BUTTON1_RELEASED:
   233             out += [('mouseup', 1, pos)]
   238             res.append(MouseEvent('mouseup', 1, pos))
   234         if bstate & curses.BUTTON2_RELEASED:
   239         if bstate & curses.BUTTON2_RELEASED:
   235             out += [('mouseup', 2, pos)]
   240             res.append(MouseEvent('mouseup', 2, pos))
   236         if bstate & curses.BUTTON3_RELEASED:
   241         if bstate & curses.BUTTON3_RELEASED:
   237             out += [('mouseup', 3, pos)]
   242             res.append(MouseEvent('mouseup', 3, pos))
   238 
   243 
   239         # reset last pos when pressed/released
   244         # Reset last pos when pressed/released
   240         if len(out) > 0 and out[-1][0] in ('mousedown', 'mouseup'):
   245         if len(res) > 0 and res[-1].name in ('mousedown', 'mouseup'):
   241             self._mouse_last_pos = None
   246             self._mouse_last_pos = None
   242 
   247 
   243         return out
   248         return res
   244 
   249 
   245     def _split_keyname_mods(self, keyname):
   250     def _split_keyname_mods(self, keyname):
   246         """Parse keynames in form "shift+tab", return (keyname, mod)."""
   251         """Parse keynames in form "shift+tab", return (keyname, mod)."""
   247         mod_set = set()
   252         mod_set = set()
   248         if '+' in keyname:
   253         if '+' in keyname: