Exemple #1
0
 def __init__(self, mgr):
     self.mgr = mgr
     self.mainwin = TextWindow(mgr,
                               32,
                               24,
                               0,
                               0,
                               kb_event=self.kb_event,
                               cursor_off=True)
     self.ctrlwin = None
     self.ctrlwin_timeout = time.time() + 20
     self.edlin = None
     self.show_offset = 0
     self.max_lines = 16
     self.f_index_str = '1234567890ABCDEFGHI'
     self.f_index = str2zx(self.f_index_str)
     self.actual_lines = 0
     self.charmap = [15] * 256
     self.build_charmap()
     self.cam = None
     self.camout = None
     self.app_state = AppState.SHOW
     self.replay_ix = 0
     self.delay_s = 3.0
     self.event = mgr.schedule_event(self.periodic, 1.0, 5.0)
     self.contrast = 0.5
     self.brightness = 1.0
     self.invert = False
     self.h_v_rot = 0  # H/V flip or rotate status as three LSB bits
     self.floyd_stb = False
     self.applied_rot = None
     self.check_show_ctrlwin()
     self.movie = []
     self.last_pic = None
Exemple #2
0
class AppShell:
    def __init__(self, mgr):
        self.mainwin = TextWindow(mgr,
                                  30,
                                  22,
                                  1,
                                  1,
                                  border=WindowBorderFrame(),
                                  kb_event=self.kb_event)
        #run('cmd',shell=True,stdout=self,stderr=self,stdin=self)
        #self.proc = Popen(['python','C:\\Users\\Holmatic\\workspace\\serial\\src\\apps\\file_browser.py'],shell=True,stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
        self.proc = Popen('cmd',
                          shell=True,
                          stdin=PIPE,
                          stdout=PIPE,
                          stderr=PIPE,
                          universal_newlines=True)
        self.revent = mgr.schedule_event(self.periodic, 0.5, 0.5)
        print("AppShell starts...")
        self.outThread = Thread(target=self.out_handler_thread,
                                args=(self.proc.stdout, ))
        self.errThread = Thread(target=self.out_handler_thread,
                                args=(self.proc.stderr, ))
        self.outThread.start()
        self.errThread.start()

    # todo exit

    def out_handler_thread(self, p):
        print("out_handler_thread starts...")
        #self.event.set()
        while True:
            # print("read data: ")
            data = p.read(1)  #.decode("utf-8")
            if not data:
                break
            z = str2zx(data)
            sys.stdout.write(data)
            sys.stdout.flush()
            for c in z:
                self.mainwin.prtchar(c)
        print("Shell Out")

    def periodic(self):
        pass  #self.event.wait(timeout=0.1)

    def kb_event(self, win, char):
        if char == 12:
            self.mainwin.close()
            app.clear()
            # TODO clear threads
        else:
            win.prtchar(char)
            s = zx2str([char])
            #if s=='\n': s='\r\n'
            self.proc.stdin.write(s)
            self.proc.stdin.flush()
Exemple #3
0
 def __init__(self,mgr):
     self.mainwin=TextWindow(mgr,30,22,1,1,border=WindowBorderFrame(),kb_event=self.kb_event, cursor_off=True)
     self.print_help()
     #run('cmd',shell=True,stdout=self,stderr=self,stdin=self)
     #self.proc = Popen(['python','C:\\Users\\Holmatic\\workspace\\serial\\src\\apps\\file_browser.py'],shell=True,stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
     self.proc = None
     self.revent=mgr.schedule_event(self.periodic,0.5,0.5)
     self.outThread = None
     self.errThread = None
Exemple #4
0
    def kb_event(self, win, zxchar):
        #win.prtchar(zxchar)
        bright = {'1': 1.5, '2': 1.2, '3': 1.0, '4': 0.83, '5': 0.67}
        contr = {'6': 0.2, '7': 0.33, '8': 0.5, '9': 0.8, '0': 1.2}
        s = zx2str([zxchar])
        if s in 'xX' or zxchar == 12:
            self.close()
            return
        elif s in 'fF':
            self.delay_s = 0.15
        elif s in 'sS':
            self.delay_s = 3.0
        elif s in 'dD':
            self.floyd_stb = not self.floyd_stb
        elif s in 'iI':
            self.invert = not self.invert
        elif s in 'rR':
            self.h_v_rot += 1

        elif s in 'pP':
            if self.app_state == AppState.SHOW:
                self.app_state = AppState.PIC_QUERY_YN
                if self.ctrlwin: self.ctrlwin.close()
                self.ctrlwin = TextWindow(self.mgr,
                                          10,
                                          1,
                                          18,
                                          19,
                                          border=WindowBorderFrame(),
                                          kb_event=self.kb_event_query,
                                          cursor_off=True)
                self.ctrlwin.prttxt(str2zx('save? Y/N', upper_inv=True))

        elif s in 'mM':
            self.movie.clear()
            self.replay_ix = 0
            if self.app_state == AppState.SHOW:
                self.app_state = AppState.MOVIE_REC
                if self.ctrlwin: self.ctrlwin.close()
                self.ctrlwin = TextWindow(self.mgr,
                                          13,
                                          1,
                                          17,
                                          19,
                                          border=WindowBorderFrame(),
                                          kb_event=self.kb_event_query,
                                          cursor_off=True)
                self.ctrlwin.prttxt(str2zx('recording', upper_inv=True))

        elif s in bright:
            self.brightness = bright[s]
        elif s in contr:
            self.contrast = contr[s]
        # TODO invers, save_pic, help, exit
        self.ctrlwin_timeout = time.time() + 3
        self.check_show_ctrlwin()
        self.event.reschedule(0.2, 5.0)
Exemple #5
0
 def __init__(self, mgr):
     self.mrg = mgr
     self.mainwin = TextWindow(mgr,
                               18,
                               12,
                               6,
                               5,
                               border=WindowBorderFrameShadow(),
                               kb_event=self.kb_event,
                               cursor_off=True)
     self.print_help()
Exemple #6
0
 def end_movie_rec(self):
     self.app_state = AppState.MOVIE_QUERY_YN
     if self.ctrlwin: self.ctrlwin.close()
     self.ctrlwin = TextWindow(self.mgr,
                               10,
                               1,
                               18,
                               19,
                               border=WindowBorderFrame(),
                               kb_event=self.kb_event_query,
                               cursor_off=True)
     self.ctrlwin.prttxt(str2zx('save? Y/N', upper_inv=True))
Exemple #7
0
class MediaViewerCam:
    def __init__(self, mgr, filepath):
        self.mgr = mgr
        self.mainwin = TextWindow(mgr,
                                  32,
                                  24,
                                  0,
                                  0,
                                  kb_event=self.kb_event,
                                  cursor_off=True)
        self.filepath = filepath
        self.delay_s = 0.25
        self.event = None
        self.pic_or_movie = bytes()
        self.pic_or_movie = filepath.open('rb').read()
        self.current_read_pos = 0
        self.show_next()
        if len(self.pic_or_movie) >= 2 * BYTES_PER_SCR:
            self.event = mgr.schedule_event(self.periodic, self.delay_s,
                                            self.delay_s)

    def show_next(self):
        if len(self.pic_or_movie) >= BYTES_PER_SCR:
            if self.current_read_pos >= len(self.pic_or_movie):
                self.current_read_pos = 0
            for row in range(NUM_ROWS):
                for col in range(BYTES_PER_ROW):
                    self.mainwin.setchar_raw(
                        self.pic_or_movie[self.current_read_pos], col, row)
                    self.current_read_pos += 1

    def periodic(self):
        self.show_next()

    def __enter__(self):
        return self

    def __exit__(self, _type, _value, _traceback):
        self.close()

    def close(self):
        if self.event:
            self.event.remove()
            self.event = None
        if self.mainwin:
            self.mainwin.close()
            self.mainwin = None

    def kb_event(self, win, zxchar):
        self.close()
Exemple #8
0
 def __init__(self, mgr):
     self.mgr = mgr
     self.mainwin = TextWindow(mgr,
                               32,
                               24,
                               0,
                               0,
                               kb_event=self.kb_event,
                               cursor_off=True)
     self.show_offset = 0
     self.max_lines = 20
     self.do_exit = False
     self.url = 'https://forum.tlienhard.com/phpBB3/viewforum.php?f=2'
     #print(r.text)
     self.show()
Exemple #9
0
 def __init__(self, mgr, filepath):
     self.mgr = mgr
     self.mainwin = TextWindow(mgr,
                               32,
                               24,
                               0,
                               0,
                               kb_event=self.kb_event,
                               cursor_off=True)
     self.filepath = filepath
     self.delay_s = 0.25
     self.event = None
     self.pic_or_movie = bytes()
     self.pic_or_movie = filepath.open('rb').read()
     self.current_read_pos = 0
     self.show_next()
     if len(self.pic_or_movie) >= 2 * BYTES_PER_SCR:
         self.event = mgr.schedule_event(self.periodic, self.delay_s,
                                         self.delay_s)
Exemple #10
0
 def check_show_ctrlwin(self):
     if not self.ctrlwin:
         self.ctrlwin = TextWindow(self.mgr,
                                   14,
                                   13,
                                   14,
                                   9,
                                   border=WindowBorderFrame(
                                       str2zx('ZX LIVE CAM')),
                                   kb_event=self.kb_event,
                                   cursor_off=True)
         self.ctrlwin.prttxt(
             str2zx('F fast S slow\n\nD dith I invrt', upper_inv=True))
         self.ctrlwin.prttxt(str2zx('\nP pic M movie\n', upper_inv=True))
         self.ctrlwin.prttxt(
             str2zx('\nR rotate\n\n1-5 brightness6-0 contrast\n\nX exit',
                    upper_inv=True))
     elif time.time() > self.ctrlwin_timeout:
         self.ctrlwin.close()
         self.ctrlwin = None
Exemple #11
0
 def __init__(self, mgr):
     self.mgr = mgr
     self.mainwin = TextWindow(mgr,
                               30,
                               22,
                               1,
                               1,
                               border=WindowBorderFrame(),
                               kb_event=self.kb_event,
                               cursor_off=True)
     self.homecwd = Path.cwd().parent / 'zxroot'
     self.cwd = self.homecwd
     self.cwdfiles = []
     self.show_offset = 0
     self.max_lines = 16
     self.f_index_str = '1234567890ABCDEFGHI'
     self.f_index = str2zx(self.f_index_str)
     self.actual_lines = 0
     self.get_dir()
     self.show_dir()
Exemple #12
0
 def __init__(self, mgr):
     self.mgr = mgr
     self.mainwin = TextWindow(mgr, 32, 20, 0, 0)
     self.inp_win = TextWindow(mgr,
                               30,
                               2,
                               1,
                               21,
                               border=WindowBorderFrame(),
                               kb_event=self.kb_event,
                               cursor_off=True)
     self.ed = None
     self.nick = 'zx-user'
     self.server = "irc.zxq.de"
     self.pword = ''
     self.port = 6667
     self.inp_mode = InpMode.MENU
     self.listener = ListenerThread(self.mainwin)
     self.choose_site()
     self.revent = mgr.schedule_event(self.periodic, 2, 2)
     self.channel = ''
Exemple #13
0
 def __init__(self, mgr):
     self.mainwin = TextWindow(mgr,
                               30,
                               22,
                               1,
                               1,
                               border=WindowBorderFrame(),
                               kb_event=self.kb_event)
     #run('cmd',shell=True,stdout=self,stderr=self,stdin=self)
     #self.proc = Popen(['python','C:\\Users\\Holmatic\\workspace\\serial\\src\\apps\\file_browser.py'],shell=True,stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
     self.proc = Popen('cmd',
                       shell=True,
                       stdin=PIPE,
                       stdout=PIPE,
                       stderr=PIPE,
                       universal_newlines=True)
     self.revent = mgr.schedule_event(self.periodic, 0.5, 0.5)
     print("AppShell starts...")
     self.outThread = Thread(target=self.out_handler_thread,
                             args=(self.proc.stdout, ))
     self.errThread = Thread(target=self.out_handler_thread,
                             args=(self.proc.stderr, ))
     self.outThread.start()
     self.errThread.start()
Exemple #14
0
 def kb_event_query(self, win, zxchar):
     #win.prtchar(zxchar)
     s = zx2str([zxchar])
     if self.app_state in (AppState.PIC_QUERY_NAME,
                           AppState.MOVIE_QUERY_NAME):
         if zxchar in (117, 118):  # enter,break
             if zxchar == 118:  # enter
                 self.edlin.kb_event(zxchar)
                 if self.app_state == AppState.PIC_QUERY_NAME:
                     if self.edlin.val:
                         # safe pic
                         name = zx2str(self.edlin.val,
                                       to_lower=True).strip()
                         #path
                         mwin = self.mgr.show_msg_win(str2zx("save pic .."))
                         p = zxpi_paths.get_current_work_path() / 'pics'
                         if not p.exists(): p.mkdir(parents=True)
                         n = p / (name + '.zxscr')
                         with n.open('wb') as f:
                             lrg = self.calc_lrg_from_array(self.last_pic)
                             nr, nc = lrg.shape
                             for row in range(nr):
                                 #for col in range(nc):
                                 f.write(bytes([v for v in lrg[row]]))
                             print("Saved to", str(n))
                         mwin.close()
                 elif self.app_state == AppState.MOVIE_QUERY_NAME:
                     if self.edlin.val:
                         # save movie
                         name = zx2str(self.edlin.val,
                                       to_lower=True).strip()
                         #path
                         pth = zxpi_paths.get_current_work_path() / 'movies'
                         if not pth.exists(): pth.mkdir(parents=True)
                         n = pth / (name + '.zxmovie')
                         mwin = self.mgr.show_msg_win(
                             str2zx("save movie .."))
                         mv_dat = bytearray()
                         with n.open('wb') as f:
                             for p in self.movie:
                                 lrg = self.calc_lrg_from_array(p)
                                 nr, nc = lrg.shape
                                 for row in range(nr):
                                     #for col in range(nc):
                                     rowdat = bytearray(
                                         [v for v in lrg[row]])
                                     mv_dat += rowdat
                                     f.write(rowdat)
                             print("Saved as", str(n))
                         self.mgr.update(0.1)
                         n = pth / (name + '.p')
                         with n.open('wb') as f:
                             f.write(
                                 create_comp_viewer(compress_scr(mv_dat)))
                         mwin.close()
             if self.edlin:
                 self.edlin.close()
                 self.edlin = None
             self.app_state = AppState.SHOW
             self.ctrlwin_timeout = 0
             if self.ctrlwin:
                 self.ctrlwin.close()
                 self.ctrlwin = None
         else:
             self.edlin.kb_event(zxchar)
     elif self.app_state in (AppState.MOVIE_REC, ):
         self.end_movie_rec()
     else:
         if s in 'yYzZ':
             if self.app_state in (AppState.PIC_QUERY_YN,
                                   AppState.MOVIE_QUERY_YN):
                 self.app_state = AppState.PIC_QUERY_NAME if self.app_state == AppState.PIC_QUERY_YN else AppState.MOVIE_QUERY_NAME
                 if self.ctrlwin: self.ctrlwin.close()
                 self.ctrlwin = TextWindow(self.mgr,
                                           12,
                                           2,
                                           18,
                                           19,
                                           border=WindowBorderFrame(),
                                           kb_event=self.kb_event_query,
                                           cursor_off=True)
                 self.ctrlwin.prttxt(str2zx('file name:', upper_inv=True))
                 self.edlin = LinEd(self.ctrlwin,
                                    0,
                                    1,
                                    11,
                                    maxchar=255,
                                    history=None)
         else:
             self.app_state = AppState.SHOW
             if self.ctrlwin:
                 self.ctrlwin.close()
                 self.ctrlwin = None
         self.event.reschedule(0.2, 5.0)
Exemple #15
0
class Updater:
    
    def __init__(self,mgr):
        self.mainwin=TextWindow(mgr,30,22,1,1,border=WindowBorderFrame(),kb_event=self.kb_event, cursor_off=True)
        self.print_help()
        #run('cmd',shell=True,stdout=self,stderr=self,stdin=self)
        #self.proc = Popen(['python','C:\\Users\\Holmatic\\workspace\\serial\\src\\apps\\file_browser.py'],shell=True,stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
        self.proc = None
        self.revent=mgr.schedule_event(self.periodic,0.5,0.5)
        self.outThread = None
        self.errThread = None

    def print_help(self):
        self.mainwin.prttxt(str2zx('\n\n',upper_inv=True ))
        self.mainwin.prttxt(str2zx('      ZXPI ONLINE UPDATER     ',inverse=True ))
        self.mainwin.prttxt(str2zx('\n\n U start update \n\n X exit\n\n',upper_inv=True ))
        
    # todo exit
    def start(self):
        self.mainwin.cls()
        self.mainwin.prttxt(str2zx('\nstart update attempt...\n',upper_inv=True ))
        self.proc = Popen( ['git','pull','origin','master']  ,shell=False,stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
        self.outThread = Thread(target=self.out_handler_thread, args=(self.proc.stdout,))
        self.errThread = Thread(target=self.out_handler_thread, args=(self.proc.stderr,))
        self.outThread.start()
        self.errThread.start()

    def end_cleanup(self):
        if self.proc is not None:
            if self.proc.poll() is not None:
                self.proc=None # done
        if self.proc is None:
            if self.outThread != None:
                self.outThread.join(3)
                self.outThread = None
            if self.errThread != None:
                self.errThread.join(3)
                self.errThread = None
        
    def close(self):
        self.mainwin.close()
        
    def out_handler_thread(self,p):
        print("out_handler_thread starts...")
        #self.event.set()
        try:
            while True:
                # print("read data: ")
                data = p.read(1)#.decode("utf-8")
                if not data:
                    break
                z=str2zx(data)
                sys.stdout.write(data)
                sys.stdout.flush()
                for c in z:
                    self.mainwin.prtchar(c)
        finally:
            print("Shell Out")
        
    def periodic(self):
        if self.proc is not None:
            # ongoing, see if done
            if self.proc.poll() is not None:
                self.end_cleanup()
                self.print_help()
                
        
        pass#self.event.wait(timeout=0.1)

    
    def kb_event(self,win,zxchar):
        s=zx2str( [zxchar] )
        if s in 'xX' or zxchar==12:
            if self.proc:
                self.proc.terminate()
            else:
                self.close()
                self.active=False
                self.mainwin.close()
                self.revent.remove()
                app.clear()
                return
        elif s in 'uU':
            if self.proc is None:
                self.start()
Exemple #16
0
class Shutdown:
    def __init__(self, mgr):
        self.mrg = mgr
        self.mainwin = TextWindow(mgr,
                                  18,
                                  12,
                                  6,
                                  5,
                                  border=WindowBorderFrameShadow(),
                                  kb_event=self.kb_event,
                                  cursor_off=True)
        self.print_help()

    def print_help(self):
        self.mainwin.prttxt(str2zx('\n', upper_inv=True))
        self.mainwin.prttxt(str2zx('  ZXPI SHUTDOWN   \n', inverse=True))
        self.mainwin.prttxt(
            str2zx('\n\n S shut down pi \n\n X return + go on\n',
                   upper_inv=True))

    def close(self):
        self.mainwin.close()

    def kb_event(self, win, zxchar):
        s = zx2str([zxchar])
        if s in 'sS' or zxchar == 12:
            if "Linux" in platform.system():
                self.mainwin.cls()
                self.mainwin.prttxt(
                    str2zx('\nshutdown initiated\n\n    good bye.',
                           upper_inv=True))
                self.mrg.update(wait_till_sync_done=True)
                subprocess.run(
                    ["sudo", "shutdown", "-h", "0"]
                )  # sudo is reqired if the process was started via /etc/rc.local
            else:
                self.mainwin.prttxt(
                    str2zx('\nshutdown not supported on %s host.' %
                           (platform.system()),
                           upper_inv=False))
        elif s in 'xX':
            self.close()
            app.clear()
            return
        elif s in 'uU':
            if self.proc is None:
                self.start()
        else:
            self.mainwin.cls()
            self.print_help()
Exemple #17
0
class AppFileBrowser:
    def __init__(self, mgr):
        self.mgr = mgr
        self.mainwin = TextWindow(mgr,
                                  30,
                                  22,
                                  1,
                                  1,
                                  border=WindowBorderFrame(),
                                  kb_event=self.kb_event,
                                  cursor_off=True)
        self.homecwd = Path.cwd().parent / 'zxroot'
        self.cwd = self.homecwd
        self.cwdfiles = []
        self.show_offset = 0
        self.max_lines = 16
        self.f_index_str = '1234567890ABCDEFGHI'
        self.f_index = str2zx(self.f_index_str)
        self.actual_lines = 0
        self.get_dir()
        self.show_dir()

    def get_dir(self):
        try:
            self.cwdfiles = [e for e in self.cwd.iterdir()]
            self.cwdfiles.sort()
        except PermissionError:
            print("PermissionError")
        self.show_offset = 0

    def show_dir(self):
        self.mainwin.cls()
        xs = self.mainwin.xsize
        # current path
        self.mainwin.prttxt(str2zx(str(self.cwd)[-xs:]))
        # directory
        self.mainwin.set_prtpos(0, 2)
        numf = len(self.cwdfiles)
        actual_lines = min(self.max_lines, numf - self.show_offset)
        for linenum in range(actual_lines):
            f = self.cwdfiles[linenum + self.show_offset]
            dirchar = 4 if f.is_dir() else ZXCHAR_BLANK
            self.mainwin.prttxt([
                self.f_index[linenum] | ZXCHAR_INV_FLG, ZXCHAR_BLANK, dirchar
            ] + str2zx(f.name[:xs - 4] + '\n'))
        self.mainwin.set_prtpos(0, self.max_lines + 2)
        # Show bas to orient
        if numf <= self.max_lines:
            self.mainwin.prttxt(str2zx('_' * xs))
        else:
            s1 = self.show_offset * xs // numf
            s2 = s1 + actual_lines * xs // numf
            for i in range(xs):
                self.mainwin.prtchar(131 if s1 <= i <= s2 else 9)
        self.mainwin.set_prtpos(1, self.max_lines + 4)
        self.mainwin.prttxt(
            str2zx('%s-%s' %
                   (self.f_index_str[0], self.f_index_str[actual_lines - 1]),
                   inverse=True))
        self.mainwin.prttxt(str2zx(':select', upper_inv=True))
        self.mainwin.prttxt(
            str2zx('  Prev',
                   upper_inv=True if self.show_offset > 0 else False))
        self.mainwin.prttxt(
            str2zx('  Next',
                   upper_inv=True if self.show_offset +
                   self.max_lines < len(self.cwdfiles) else False))
        self.mainwin.prttxt(
            str2zx('  Up', upper_inv=True if self.cwd.parents else False))

    def kb_event(self, win, zxchar):
        #win.prtchar(zxchar)
        s = zx2str([zxchar])
        redraw = False
        if s in 'nN':
            self.show_offset += self.max_lines
            redraw = True
        elif zxchar == 12:  # break
            mwin = self.mgr.show_msg_win(str2zx("exit. bye."))
            raise Exception('Exit')
        elif s in 'pP':
            self.show_offset -= self.max_lines
            redraw = True
        elif s in 'uUxX':
            if self.cwd.parents:
                self.cwd = self.cwd.parents[0]
                self.get_dir()
                redraw = True
        elif s in 'hH':  # Home directory
            self.cwd = self.homecwd
            self.get_dir()
            redraw = True
        elif s in 'wW':
            self.mgr.show_dialog(str2zx('press NEWLINE', upper_inv=True))
        elif zxchar in self.f_index:
            ix = self.f_index.index(zxchar) + self.show_offset
            if ix < len(self.cwdfiles):
                fi = self.cwdfiles[ix]
                if fi.is_dir():
                    self.cwd = fi
                    self.get_dir()
                    redraw = True
                elif fi.suffix.lower() == '.p':
                    name = str(fi)
                    print("LOAD ", name)
                    mwin = self.mgr.show_msg_win(
                        str2zx("load %s .." % (fi.stem)))
                    mwin.close()
                    self.mgr.server.load_p_file(name)
                    #time.sleep(0.5) # todo remove, was just for diag
                elif fi.suffix.lower() == '.py':
                    mwin = self.mgr.show_msg_win(
                        str2zx("open %s .." % (fi.stem)))
                    try:
                        spath = self.cwdfiles[ix]
                        target = Path.cwd(
                        ) / 'apps' / 'tmp' / self.cwdfiles[ix].name
                        if spath != target: copyfile(str(spath), str(target))
                        print("Copy from ", str(spath))
                        print("Copy to ", str(target))
                        module = "apps.tmp." + fi.stem  # we are already in apps
                        newmod = importlib.import_module(module)
                        importlib.reload(newmod)
                        mwin.close()
                        newmod.start(self.mgr)
                    except Exception as e:
                        mwin.close()
                        print(e)
                        traceback.print_exc()
                        self.mgr.show_dialog(str2zx("error loading module"))
#                    eval("print(globals())")
#                   print("Eval GLOB",modcmd)
#                  eval("print(globals())", globals())
#                 r=eval(modcmd, globals())
#                print("LOADed PYTHON ")
                elif fi.suffix.lower() in ('.zxscr', '.zxmovie'):
                    try:
                        apps.media_viewer.start(self.mgr, fi)
                    except Exception as e:
                        print(e)
                        traceback.print_exc()
                        self.mgr.show_dialog(str2zx("error showing file"))

        if redraw:

            self.show_offset = min(self.show_offset, len(self.cwdfiles) - 2)
            self.show_offset = max(0, self.show_offset)
            self.show_dir()
Exemple #18
0
class AppPiCam:
    def __init__(self, mgr):
        self.mgr = mgr
        self.mainwin = TextWindow(mgr,
                                  32,
                                  24,
                                  0,
                                  0,
                                  kb_event=self.kb_event,
                                  cursor_off=True)
        self.ctrlwin = None
        self.ctrlwin_timeout = time.time() + 20
        self.edlin = None
        self.show_offset = 0
        self.max_lines = 16
        self.f_index_str = '1234567890ABCDEFGHI'
        self.f_index = str2zx(self.f_index_str)
        self.actual_lines = 0
        self.charmap = [15] * 256
        self.build_charmap()
        self.cam = None
        self.camout = None
        self.app_state = AppState.SHOW
        self.replay_ix = 0
        self.delay_s = 3.0
        self.event = mgr.schedule_event(self.periodic, 1.0, 5.0)
        self.contrast = 0.5
        self.brightness = 1.0
        self.invert = False
        self.h_v_rot = 0  # H/V flip or rotate status as three LSB bits
        self.floyd_stb = False
        self.applied_rot = None
        self.check_show_ctrlwin()
        self.movie = []
        self.last_pic = None

    def __enter__(self):
        return self

    def __exit__(self, _type, _value, _traceback):
        self.close()

    def close(self):
        self.app_state = AppState.STOP
        if self.event:
            self.event.remove()
            self.event = None
        if self.camout is not None:
            self.camout.close()
            self.camout = None
        if self.cam is not None:
            self.cam.close()
            self.cam = None
        if self.mainwin:
            self.mainwin.close()
            self.mainwin = None
        if self.ctrlwin:
            self.ctrlwin.close()
            self.ctrlwin = None

    def check_show_ctrlwin(self):
        if not self.ctrlwin:
            self.ctrlwin = TextWindow(self.mgr,
                                      14,
                                      13,
                                      14,
                                      9,
                                      border=WindowBorderFrame(
                                          str2zx('ZX LIVE CAM')),
                                      kb_event=self.kb_event,
                                      cursor_off=True)
            self.ctrlwin.prttxt(
                str2zx('F fast S slow\n\nD dith I invrt', upper_inv=True))
            self.ctrlwin.prttxt(str2zx('\nP pic M movie\n', upper_inv=True))
            self.ctrlwin.prttxt(
                str2zx('\nR rotate\n\n1-5 brightness6-0 contrast\n\nX exit',
                       upper_inv=True))
        elif time.time() > self.ctrlwin_timeout:
            self.ctrlwin.close()
            self.ctrlwin = None

    def show_help(self):
        self.mainwin.prttxt(
            str2zx('\n      ZX LIVE CAMERA       \n\n', inverse=True))
        self.mainwin.prttxt(
            str2zx(
                '\n\n NEWLINE to start\n\n F fast update    S slow update\n\n D dithering\n\n I invert',
                upper_inv=True))
        self.mainwin.prttxt(
            str2zx('\n\n R rotate\n\n 1-5 bright\n\n 6-0 contrast\n\n X exit',
                   upper_inv=True))

    def periodic(self):
        startt = time.time()
        if self.app_state == AppState.SHOW:
            if self.ctrlwin and time.time() > self.ctrlwin_timeout:
                self.ctrlwin.close()
                self.ctrlwin = None
        if self.app_state in (AppState.SHOW, AppState.MOVIE_REC):
            self.last_pic = self.get_img_mono()
            self.mgr.update(0.08)  # allow for kb inp response
            if self.app_state in (AppState.SHOW, AppState.MOVIE_REC):
                lrg = self.calc_lrg_from_array(self.last_pic)
                self.show_lrg(lrg)
                if self.app_state == AppState.MOVIE_REC:
                    if len(self.movie) < 50:
                        self.movie.append(self.last_pic)
                        self.ctrlwin.set_prtpos(0, 0)
                        self.ctrlwin.prttxt(
                            str2zx('recording %02d' % len(self.movie),
                                   upper_inv=True))
                    else:
                        self.end_movie_rec()
                evt_t = time.time() - startt
                self.event.reschedule(max(0.08, self.delay_s - evt_t), 5.0)
        elif self.app_state in (AppState.MOVIE_QUERY_YN,
                                AppState.MOVIE_QUERY_NAME):
            if len(self.movie):
                if self.replay_ix >= len(self.movie): self.replay_ix = 0
                lrg = self.calc_lrg_from_array(self.movie[self.replay_ix])
                self.show_lrg(lrg)
                self.replay_ix += 1
                evt_t = time.time() - startt
                self.event.reschedule(max(0.08, self.delay_s - evt_t), 5.0)

    def build_charmap(self):
        for pul in range(4):
            for pur in range(4):
                for pll in range(4):
                    for plr in range(4):
                        c = 15
                        ix = pul * 64 + pur * 16 + pll * 4 + plr
                        al = (pul, pur, pll, plr)
                        up = (pul, pur)
                        lo = (pll, plr)
                        if 0 not in al and 3 not in al:
                            # just grey
                            if sum(al) / len(al) > 1.5:
                                c = 8  # fits to brighter edges
                            else:
                                c = 136  # fits to darker edges

                        elif 0 not in up and 3 not in up and 2 not in lo and 3 not in lo:
                            # upper grey, low black
                            c = 138
                        elif 0 not in up and 3 not in up and 0 not in lo and 1 not in lo:
                            # upper grey, low white
                            c = 10
                        elif 0 not in lo and 3 not in lo and 2 not in up and 3 not in up:
                            # low grey, upper black
                            c = 137
                        elif 0 not in lo and 3 not in lo and 0 not in up and 1 not in up:
                            # low grey, upper white
                            c = 9
                        else:
                            # binary
                            c = 0
                            if pul <= 1: c += 1
                            if pur <= 1: c += 2
                            if pll <= 1: c += 4
                            if plr <= 1: c = c ^ 0x87
                        self.charmap[ix] = c
        #print (self.charmap)

    def get_img_mono(self):
        a = None
        if cam_available:
            if self.cam is None:
                self.cam = picamera.PiCamera()
            if self.camout is None:
                self.camout = picamera.array.PiYUVArray(self.cam)
                self.cam.resolution = (64, 48)
            else:
                self.camout.truncate(0)
            rotate = self.h_v_rot & 1
            if rotate != self.applied_rot:
                self.cam.resolution = (48, 64) if rotate else (64, 48)
                self.applied_rot = rotate
            self.cam.capture(self.camout, 'yuv', use_video_port=True)
            a = self.camout.array[:, :, 0]
            if rotate: a = numpy.transpose(a)
        else:
            a = pickle.loads(p)
        return a

    def show_lrg(self, a):
        nr, nc = a.shape
        for row in range(nr):
            for col in range(nc):
                self.mainwin.setchar_raw(a[row, col], col, row)

    def calc_lrg_from_array(self, a):
        #calculate the mean value etc
        t = time.time()

        if self.h_v_rot & 4: a = numpy.fliplr(a)  # H flip
        if self.h_v_rot & 2: a = numpy.flipud(a)  # V flip
        if self.invert: a = 255 - a

        m = a.mean() / self.brightness
        s = a.std() * self.contrast * (1 if cam_available else random.gauss(
            1.0, 0.1))  # add some dynamics if no camera is there
        l0 = m - s
        l1 = m
        l2 = m + s
        nr, nc = a.shape

        # optional flody-steinberg
        if self.floyd_stb:
            l0 = max(0, int(m - 2 * s))
            l2 = min(255, int(m + 2 * s))
            for row in range(0, nr):
                for col in range(0, nc):
                    p = a[row, col]
                    n = l2 if p > l1 else l0
                    err = p - n
                    a[row, col] = n
                    if col < nc - 1:
                        a[row, col + 1] += err * 7 // 16
                    if row < nr - 1:
                        if col >= 1:
                            a[row + 1, col - 1] += err * 3 // 16
                        a[row + 1, col] += err * 5 // 16
                        if col < nc - 1:
                            a[row + 1, col + 1] += err * 1 // 16

        brightmap = [
            0 if b <= l0 else 3 if b >= l2 else 1 if b < l1 else 2
            for b in range(256)
        ]
        #print(brightmap)
        #print(a.mean(),a.std())
        va = numpy.zeros((nr // 2, nc // 2), dtype=int)

        for row in range(0, nr, 2):
            for col in range(0, nc, 2):
                # get the four points that make up a character
                code = 0
                for b in (a[row, col], a[row, col + 1], a[row + 1,
                                                          col], a[row + 1,
                                                                  col + 1]):
                    code *= 4
                    if 0:  # this seems to be much slower than the lookup below!
                        if b < l0:
                            c = 0
                        elif b > l2:
                            c = 3
                        elif b < l1:
                            c = 1
                        else:
                            c = 2
                        code += c
                        if c != brightmap[b]: print("FAIL")
                    else:
                        code += brightmap[b]
                va[row // 2, col // 2] = self.charmap[code]
                #self.mainwin.setchar_raw(self.charmap[code], col//2, row//2)
        #print("Display took %.2fus."%((time.time()-t)*1000000) )
        # now er have an 8bit code that we map for the proper char
        return va

    def end_movie_rec(self):
        self.app_state = AppState.MOVIE_QUERY_YN
        if self.ctrlwin: self.ctrlwin.close()
        self.ctrlwin = TextWindow(self.mgr,
                                  10,
                                  1,
                                  18,
                                  19,
                                  border=WindowBorderFrame(),
                                  kb_event=self.kb_event_query,
                                  cursor_off=True)
        self.ctrlwin.prttxt(str2zx('save? Y/N', upper_inv=True))

    def kb_event(self, win, zxchar):
        #win.prtchar(zxchar)
        bright = {'1': 1.5, '2': 1.2, '3': 1.0, '4': 0.83, '5': 0.67}
        contr = {'6': 0.2, '7': 0.33, '8': 0.5, '9': 0.8, '0': 1.2}
        s = zx2str([zxchar])
        if s in 'xX' or zxchar == 12:
            self.close()
            return
        elif s in 'fF':
            self.delay_s = 0.15
        elif s in 'sS':
            self.delay_s = 3.0
        elif s in 'dD':
            self.floyd_stb = not self.floyd_stb
        elif s in 'iI':
            self.invert = not self.invert
        elif s in 'rR':
            self.h_v_rot += 1

        elif s in 'pP':
            if self.app_state == AppState.SHOW:
                self.app_state = AppState.PIC_QUERY_YN
                if self.ctrlwin: self.ctrlwin.close()
                self.ctrlwin = TextWindow(self.mgr,
                                          10,
                                          1,
                                          18,
                                          19,
                                          border=WindowBorderFrame(),
                                          kb_event=self.kb_event_query,
                                          cursor_off=True)
                self.ctrlwin.prttxt(str2zx('save? Y/N', upper_inv=True))

        elif s in 'mM':
            self.movie.clear()
            self.replay_ix = 0
            if self.app_state == AppState.SHOW:
                self.app_state = AppState.MOVIE_REC
                if self.ctrlwin: self.ctrlwin.close()
                self.ctrlwin = TextWindow(self.mgr,
                                          13,
                                          1,
                                          17,
                                          19,
                                          border=WindowBorderFrame(),
                                          kb_event=self.kb_event_query,
                                          cursor_off=True)
                self.ctrlwin.prttxt(str2zx('recording', upper_inv=True))

        elif s in bright:
            self.brightness = bright[s]
        elif s in contr:
            self.contrast = contr[s]
        # TODO invers, save_pic, help, exit
        self.ctrlwin_timeout = time.time() + 3
        self.check_show_ctrlwin()
        self.event.reschedule(0.2, 5.0)

    def kb_event_query(self, win, zxchar):
        #win.prtchar(zxchar)
        s = zx2str([zxchar])
        if self.app_state in (AppState.PIC_QUERY_NAME,
                              AppState.MOVIE_QUERY_NAME):
            if zxchar in (117, 118):  # enter,break
                if zxchar == 118:  # enter
                    self.edlin.kb_event(zxchar)
                    if self.app_state == AppState.PIC_QUERY_NAME:
                        if self.edlin.val:
                            # safe pic
                            name = zx2str(self.edlin.val,
                                          to_lower=True).strip()
                            #path
                            mwin = self.mgr.show_msg_win(str2zx("save pic .."))
                            p = zxpi_paths.get_current_work_path() / 'pics'
                            if not p.exists(): p.mkdir(parents=True)
                            n = p / (name + '.zxscr')
                            with n.open('wb') as f:
                                lrg = self.calc_lrg_from_array(self.last_pic)
                                nr, nc = lrg.shape
                                for row in range(nr):
                                    #for col in range(nc):
                                    f.write(bytes([v for v in lrg[row]]))
                                print("Saved to", str(n))
                            mwin.close()
                    elif self.app_state == AppState.MOVIE_QUERY_NAME:
                        if self.edlin.val:
                            # save movie
                            name = zx2str(self.edlin.val,
                                          to_lower=True).strip()
                            #path
                            pth = zxpi_paths.get_current_work_path() / 'movies'
                            if not pth.exists(): pth.mkdir(parents=True)
                            n = pth / (name + '.zxmovie')
                            mwin = self.mgr.show_msg_win(
                                str2zx("save movie .."))
                            mv_dat = bytearray()
                            with n.open('wb') as f:
                                for p in self.movie:
                                    lrg = self.calc_lrg_from_array(p)
                                    nr, nc = lrg.shape
                                    for row in range(nr):
                                        #for col in range(nc):
                                        rowdat = bytearray(
                                            [v for v in lrg[row]])
                                        mv_dat += rowdat
                                        f.write(rowdat)
                                print("Saved as", str(n))
                            self.mgr.update(0.1)
                            n = pth / (name + '.p')
                            with n.open('wb') as f:
                                f.write(
                                    create_comp_viewer(compress_scr(mv_dat)))
                            mwin.close()
                if self.edlin:
                    self.edlin.close()
                    self.edlin = None
                self.app_state = AppState.SHOW
                self.ctrlwin_timeout = 0
                if self.ctrlwin:
                    self.ctrlwin.close()
                    self.ctrlwin = None
            else:
                self.edlin.kb_event(zxchar)
        elif self.app_state in (AppState.MOVIE_REC, ):
            self.end_movie_rec()
        else:
            if s in 'yYzZ':
                if self.app_state in (AppState.PIC_QUERY_YN,
                                      AppState.MOVIE_QUERY_YN):
                    self.app_state = AppState.PIC_QUERY_NAME if self.app_state == AppState.PIC_QUERY_YN else AppState.MOVIE_QUERY_NAME
                    if self.ctrlwin: self.ctrlwin.close()
                    self.ctrlwin = TextWindow(self.mgr,
                                              12,
                                              2,
                                              18,
                                              19,
                                              border=WindowBorderFrame(),
                                              kb_event=self.kb_event_query,
                                              cursor_off=True)
                    self.ctrlwin.prttxt(str2zx('file name:', upper_inv=True))
                    self.edlin = LinEd(self.ctrlwin,
                                       0,
                                       1,
                                       11,
                                       maxchar=255,
                                       history=None)
            else:
                self.app_state = AppState.SHOW
                if self.ctrlwin:
                    self.ctrlwin.close()
                    self.ctrlwin = None
            self.event.reschedule(0.2, 5.0)
Exemple #19
0
class IrcClient:
    def __init__(self, mgr):
        self.mgr = mgr
        self.mainwin = TextWindow(mgr, 32, 20, 0, 0)
        self.inp_win = TextWindow(mgr,
                                  30,
                                  2,
                                  1,
                                  21,
                                  border=WindowBorderFrame(),
                                  kb_event=self.kb_event,
                                  cursor_off=True)
        self.ed = None
        self.nick = 'zx-user'
        self.server = "irc.zxq.de"
        self.pword = ''
        self.port = 6667
        self.inp_mode = InpMode.MENU
        self.listener = ListenerThread(self.mainwin)
        self.choose_site()
        self.revent = mgr.schedule_event(self.periodic, 2, 2)
        self.channel = ''

    def periodic(self):
        if self.inp_mode == InpMode.ONLINE and not self.listener.conn:
            self.mainwin.prttxt(str2zx('\n\nDISCONNECT\n\n', upper_inv=True))
            self.disconnect()
            self.mgr.update(1.5)
            self.choose_site()

    def choose_site(self):
        self.mainwin.cls()
        self.mainwin.prttxt(str2zx('\n\n', upper_inv=True))
        self.mainwin.prttxt(
            str2zx('       ZXPI IRC CHAT CLIENT     ', inverse=True))
        self.mainwin.prttxt(
            str2zx('\n\n N >nick   (%s)' % (self.nick), upper_inv=True))
        self.mainwin.prttxt(
            str2zx('\n\n S >server (%s)' % (self.server), upper_inv=True))
        self.mainwin.prttxt(
            str2zx('\n\n P >port   (%d)' % (self.port), upper_inv=True))
        self.mainwin.prttxt(
            str2zx('\n\n W >password (%s)' %
                   ('*' * len(self.pword) if len(self.pword) else 'none'),
                   upper_inv=True))
        self.mainwin.prttxt(
            str2zx('\n\n C connect \n\n\n X exit\n\n', upper_inv=True))
        self.inp_win.cls()
        self.inp_win.prttxt(str2zx('please select'))

    def connect(self):
        self.revent.reschedule(15.0, 1.0)  # give 3 sec for connect
        self.listener.start((self.server, self.port), self.nick, self.pword)
        self.inp_mode = InpMode.ONLINE
        self.mainwin.cls()
        self.mainwin.prttxt(
            str2zx('\n\nCONNECT to %s..\n\n' % (self.server), upper_inv=True))

    def disconnect(self):
        self.listener.close()
        self.inp_mode = InpMode.MENU

    def close(self):
        self.revent.remove()
        self.disconnect()
        if self.ed: self.ed.close()
        self.mainwin.close()
        self.inp_win.close()

    def kb_event(self, win, char):
        if self.inp_mode == InpMode.MENU:
            if char == 56:  # S
                self.inp_win.cls()
                self.inp_win.prttxt(
                    str2zx(' please enter server address: ', inverse=True))
                self.ed = LinEd(self.inp_win, 0, 1, 29, 255,
                                bytes(str2zx(self.server)))
                self.inp_mode = InpMode.INP_SRV
            elif char == 53:  # P
                self.inp_win.cls()
                self.inp_win.prttxt(
                    str2zx(' please enter port number: ', inverse=True))
                self.ed = LinEd(self.inp_win, 0, 1, 6, 5,
                                bytes(str2zx(str(self.port))))
                self.inp_mode = InpMode.INP_PORT
            elif char == 60:  # W
                self.inp_win.cls()
                self.inp_win.prttxt(
                    str2zx(' please enter pass word: ', inverse=True))
                self.ed = LinEd(self.inp_win, 0, 1, 29, 255)
                self.inp_mode = InpMode.INP_PWORD
            elif char == 51:  # N
                self.inp_win.cls()
                self.inp_win.prttxt(
                    str2zx(' please enter nickname: ', inverse=True))
                self.ed = LinEd(self.inp_win, 0, 1, 29, 255,
                                bytes(str2zx(self.nick)))
                self.inp_mode = InpMode.INP_NICK
            elif char == 40:  # C
                self.inp_win.cls()
                self.inp_win.prttxt(
                    str2zx('   /join /part /quit /help', inverse=False))
                self.ed = LinEd(self.inp_win, 0, 1, 29, 255)
                self.connect()
            elif char == 61 or char == 117:  # x or break
                self.close()
                app.clear()
                # TODO clear threads
        elif self.inp_mode in (InpMode.INP_SRV, InpMode.INP_PORT,
                               InpMode.INP_PWORD, InpMode.INP_NICK):
            if char in (117, 118):  # enter,break
                if char == 118:  # enter
                    if self.inp_mode == InpMode.INP_SRV:
                        if self.ed.val.strip():
                            self.server = zx2str(self.ed.val, to_lower=True)
                    if self.inp_mode == InpMode.INP_NICK:
                        if self.ed.val.strip():
                            self.nick = zx2str(self.ed.val, to_lower=True)
                    elif self.inp_mode == InpMode.INP_PWORD:
                        self.pword = zx2str(self.ed.val, to_lower=True)
                    else:
                        try:
                            self.port = int(zx2str(self.ed.val))
                        except:
                            pass
                self.ed.close()
                self.ed = None
                self.inp_mode = InpMode.MENU
                self.choose_site()
            else:
                self.ed.kb_event(char)
        elif self.inp_mode == InpMode.ONLINE:
            if char == 118:  # enter
                s = zx2str(self.ed.val, to_lower=True).strip()
                self.ed.clear()
                if s.startswith("/q"):
                    self.listener.send('QUIT :bye\r\n')
                    time.sleep(0.1)
                    self.disconnect()
                    self.ed.close()
                    self.ed = None
                    self.inp_mode = InpMode.MENU
                    self.choose_site()
                elif s.startswith("/join ") and len(s.split()) == 2:
                    self.channel = '#' + s.split()[1]
                    self.listener.send('JOIN %s\r\n' % (self.channel))
                elif s.startswith("/part") and self.channel:
                    self.listener.send('PART %s\r\n' % (self.channel))
                    self.channel = ''
                elif s.startswith("/list"):
                    self.listener.send('LIST\r\n')
                elif s.startswith("/names"):
                    self.listener.send('NAMES %s\r\n' % (self.channel))
                elif s.startswith("/h"):
                    self.mainwin.cls()
                    z = str2zx('\n\n HELP on the irc client usage \n\n',
                               inverse=True)
                    z += str2zx(
                        '\n/JOIN <mychannel>  join channel\n      (just omit the hash tag)\n',
                        upper_inv=True)
                    z += str2zx('\n/PART   leave the channel\n',
                                upper_inv=True)
                    z += str2zx('\n/NAMES  show who is there\n',
                                upper_inv=True)
                    z += str2zx('\n/LIST   list all channels\n',
                                upper_inv=True)
                    z += str2zx('\n/QUIT   exit from server\n', upper_inv=True)
                    z += str2zx(
                        '\n after joining, type a message   to all users in that channel\n',
                        upper_inv=True)
                    z += str2zx('\n        have fun       \n', inverse=True)
                    self.mainwin.prttxt(z)
                elif s.startswith("/"):
                    z = str2zx('\n??? unknown cmd %s' % (s.strip()))
                    self.mainwin.prttxt(z)
                else:
                    self.listener.send('PRIVMSG %s :%s\r\n' %
                                       (self.channel, s))
                    z = str2zx('\n<%s> %s' % (self.nick, s.strip()))
                    self.mainwin.prttxt(z)
            else:
                self.ed.kb_event(char)
Exemple #20
0
class AppWebZxForumDe:
    def __init__(self, mgr):
        self.mgr = mgr
        self.mainwin = TextWindow(mgr,
                                  32,
                                  24,
                                  0,
                                  0,
                                  kb_event=self.kb_event,
                                  cursor_off=True)
        self.show_offset = 0
        self.max_lines = 20
        self.do_exit = False
        self.url = 'https://forum.tlienhard.com/phpBB3/viewforum.php?f=2'
        #print(r.text)
        self.show()

    def show(self):
        self.mainwin.cls()
        self.mainwin.prttxt(
            str2zx("wait for \n" + self.url[:28] + '..\n', upper_inv=False))
        self.mgr.update(wait_till_sync_done=True)

        while True:
            try:
                r = requests.get(self.url, timeout=7.0)
                if r.status_code == requests.codes.ok: break
                self.mainwin.prttxt(
                    str2zx("retrieved %d, try again..\n" % (r.status_code),
                           upper_inv=False))
            except ConnectionError as e:
                self.mainwin.prttxt(
                    str2zx("error %s, try again..\n" % (str(e)),
                           upper_inv=False))
            except requests.RequestException as e:
                self.mainwin.prttxt(
                    str2zx("retrieved %s, try again..\n" % (str(e)),
                           upper_inv=False))
            self.mgr.update(0.5)
            if self.do_exit: return

        self.mainwin.prttxt(str2zx("parse..\n", upper_inv=False))
        self.mgr.update(wait_till_sync_done=True)
        if self.do_exit: return
        #print(r.text)
        parser = MyHTMLParser()
        parser.feed(r.text)
        self.mainwin.cls()
        self.mainwin.prttxt(str2zx(self.url[:32], inverse=True))
        self.mainwin.prttxt([ZXCHAR_NEWLINE] + [10] * 32)
        d = parser.out_data
        lines = 0
        for entry in d:
            hd, nm, dt = entry
            numchar = len(hd) + len(nm) + len(dt) + 1
            numlines = (numchar + 31) // 32
            addspc = ' ' * (32 * numlines - numchar)
            if lines + numlines + 1 > self.max_lines:
                break
            lines += numlines + 1
            self.mainwin.prttxt(str2zx(hd, upper_inv=False))
            self.mainwin.prttxt(str2zx(addspc))
            self.mainwin.prttxt(str2zx(nm, inverse=True))
            self.mainwin.prttxt(str2zx(' '))
            self.mainwin.prttxt(str2zx(dt, inverse=False))
            self.mainwin.prttxt([10] * 32)

    def close(self):
        if self.mainwin is not None:
            self.mainwin.close()
            self.mainwin = None

    def kb_event(self, win, zxchar):
        #win.prtchar(zxchar)
        s = zx2str([zxchar])

        if s in 'xXuU' or zxchar == 12:
            self.do_exit = True
            self.close()
        else:
            self.show()