Example #1
0
class Monitor(IOBase):
    def __init__(self, cols=40, rows=4):
        self.textbuffer = TextBuffer(cols, rows)

    def read(self, size):
        return None

    def write(self, byteslike):
        with open("write.txt", 'wa') as dumpfile:
            for byte in byteslike:
                dumpfile.write(str(byte) + ' ' + chr(byte) + '\n')

        self.textbuffer.write(byteslike)

        self.dump_screen()
        self.dump_lines()
        self.dump_wrapped()

        return len(byteslike)

    def dump_screen(self):
        lines = []
        line_dict = self.textbuffer.pop()
        for y in range(self.textbuffer.rows):
            if y in line_dict:
                lines.append(line_dict[y] + '\n')
            else:
                lines.append('*' * self.textbuffer.cols + '\n')

        lines.append('\n')
        lines.append(str(self.textbuffer.offset) + '\n')
        lines.append(self.textbuffer.previous_char + '\n')
        lines.append(str(len(line_dict)) + '\n')

        with open("screen.txt", 'w') as dumpfile:
            for line in lines:
                dumpfile.write(line)

    def dump_lines(self):
        with open("lines.txt", 'w') as dumpfile:
            for line in self.textbuffer.lines:
                dumpfile.write(line + '\n')

    def dump_wrapped(self):
        with open("wrapped.txt", 'w') as dumpfile:
            for wrapped_lines in self.textbuffer.wrapped:
                for line in wrapped_lines:
                    dumpfile.write(line + '\n')
Example #2
0
File: main.py Project: echo8/editor
def run():
    (window_size, f) = get_args()

    tb = TextBuffer()
    if f:
        tb.load(f)

    sdl2.ext.init()
    window = sdl2.ext.Window(WINDOW_TITLE, size=window_size)
    window.show()

    factory = sdl2.ext.SpriteFactory(sdl2.ext.SOFTWARE)

    font_img = factory.from_image(FONT_IMG_PATH)
    sdl2.SDL_SetColorKey(
        font_img.surface, sdl2.SDL_TRUE,
        sdl2.SDL_MapRGB(font_img.surface.format, COLOR_KEY_R, COLOR_KEY_G,
                        COLOR_KEY_B))
    font = sdl2.ext.BitmapFont(font_img, FONT_SIZE, mapping=FONT_MAPPING)

    sb = StatusBar(window, tb, font, STATUS_BAR_COLOR,
                   (STATUS_BAR_BORDER_TOP, STATUS_BAR_BORDER_RIGHT,
                    STATUS_BAR_BORDER_BOTTOM, STATUS_BAR_BORDER_LEFT))
    ta = TextArea(window, font, tb,
                  (TEXT_AREA_BORDER_TOP, TEXT_AREA_BORDER_RIGHT,
                   sb.height + TEXT_AREA_BORDER_BOTTOM, TEXT_AREA_BORDER_LEFT),
                  TEXT_AREA_LINE_SPACING)
    state = EditState(Editor(None, window, ta, sb))

    sdl2.SDL_StartTextInput()

    while True:
        start = sdl2.SDL_GetTicks()
        state = state.update(sdl2.ext.get_events())
        if state is None:
            break
        ticks = sdl2.SDL_GetTicks() - start
        if ticks < 1000 / FRAMES_PER_SECOND:
            sdl2.SDL_Delay((1000 / FRAMES_PER_SECOND) - ticks)

    sdl2.SDL_StopTextInput()
    sdl2.ext.quit()
    return 0
Example #3
0
 def init_input(self, label, text=None):
     self.input_label = label
     self.input = TextArea(
         self.window,
         self.font,
         TextBuffer(text),
         window_border=(self.window.size[1] - self.height + self.border[0],
                        self.border[1], self.border[2],
                        (self.font.size[0] * len(label)) +
                        (2 * self.border[3])),
         line_spacing=0)
Example #4
0
    def __init__(self):

        self.textbuffer = TextBuffer(cols, rows)

        # make the framebuffer we draw into the size of one line of text as that's all we need
        self.buf = bytearray(screen_width * font_height // 8)
        # the screen defaults to portrait and we want to use it in landscape so we have to rotate as we go, unfortunately. that's why dimensions look swapped around
        self.fb = FrameBuffer(self.buf, font_height, screen_width, MONO_HLSB)

        sck = Pin(18, Pin.OUT)
        mosi = Pin(23, Pin.OUT)
        miso = Pin(19, Pin.IN)
        spi = SPI(2,
                  baudrate=80000000,
                  polarity=0,
                  phase=0,
                  sck=sck,
                  mosi=mosi,
                  miso=miso)

        cs = Pin(5, Pin.OUT)
        dc = Pin(17, Pin.OUT)
        rst = Pin(27, Pin.OUT)
        busy = Pin(35, Pin.IN)

        self.epd = EPD(spi, cs, dc, rst, busy)
        self.epd.init()

        self.clear_screen()

        # we were in slow mode for the initial clear on startup, we're now going to fast mode as that's the most likely one we'll need next
        self.mode = 'slow'
        self.set_fast()

        self.running = False

        self.last_change = None
Example #5
0
class Screen:
    def __init__(self):

        self.textbuffer = TextBuffer(cols, rows)

        # make the framebuffer we draw into the size of one line of text as that's all we need
        self.buf = bytearray(screen_width * font_height // 8)
        # the screen defaults to portrait and we want to use it in landscape so we have to rotate as we go, unfortunately. that's why dimensions look swapped around
        self.fb = FrameBuffer(self.buf, font_height, screen_width, MONO_HLSB)

        sck = Pin(18, Pin.OUT)
        mosi = Pin(23, Pin.OUT)
        miso = Pin(19, Pin.IN)
        spi = SPI(2,
                  baudrate=80000000,
                  polarity=0,
                  phase=0,
                  sck=sck,
                  mosi=mosi,
                  miso=miso)

        cs = Pin(5, Pin.OUT)
        dc = Pin(17, Pin.OUT)
        rst = Pin(27, Pin.OUT)
        busy = Pin(35, Pin.IN)

        self.epd = EPD(spi, cs, dc, rst, busy)
        self.epd.init()

        self.clear_screen()

        # we were in slow mode for the initial clear on startup, we're now going to fast mode as that's the most likely one we'll need next
        self.mode = 'slow'
        self.set_fast()

        self.running = False

        self.last_change = None

    def write(self, byteslike):
        self.textbuffer.write(byteslike)
        self.debounce_update()

    def set_slow(self):
        if self.mode == 'slow':
            return

        self.mode = 'slow'
        self.epd.set_slow()

    def set_fast(self):
        if self.mode == 'fast':
            return

        self.mode = 'fast'
        self.epd.set_fast()

    def plot(self, x, y):
        # rotate 90 degrees on the fly
        self.fb.pixel(font_height - 1 - y, x, 0)

    def plot_inverse(self, x, y):
        # rotate 90 degrees
        self.fb.pixel(font_height - 1 - y, x, 1)

    def debounce_update(self):
        self.last_change = time.ticks_ms()

    def update_screen(self, tmr=None):
        self.last_change = None

        if not self.running:
            return

        # TODO: keep some performance stats somewhere

        # the changed lines. keys are row indexes, values are line strings
        lines_dict = self.textbuffer.pop()

        # slow update if the entire screen changed (gives it a chance to remove the ghosting), otherwise fast for partial updates
        if len(lines_dict) == self.textbuffer.rows:
            self.set_slow()
        else:
            self.set_fast()

        cursor_x = self.textbuffer.x()
        cursor_y = self.textbuffer.y()

        # keep both buffers in the display's controller in sync
        for i in range(2):
            self._update_buffer(lines_dict, cursor_x, cursor_y)

            # display only one of the buffers
            if i == 0:
                self.epd.display_frame()

    def _update_buffer(self, lines_dict, cursor_x, cursor_y):
        for row_index, line in lines_dict.items():
            # clear the framebuffer because it now represents this row
            self.fb.fill(1)

            # print the text
            font.draw_line(line.encode('ascii'), self.plot)

            if row_index == cursor_y:
                # draw the cursor (rotated 90 degrees)
                self.fb.fill_rect(0, cursor_x * font_width, font_height,
                                  font_width, 0)

                # if the cursor is on a character, also draw that character inverted
                if cursor_x < len(line):
                    font.draw_line(line[cursor_x].encode('ascii'),
                                   self.plot_inverse, cursor_x * font_width, 1)

            # copy this row to the screen's buffer (rotated 90 degrees)
            self.epd.set_frame_memory(
                self.buf, screen_height - ((row_index + 1) * font_height), 0,
                font_height, screen_width)

    def clear_screen(self):
        self.fb.fill(1)

        # clear both buffers
        for i in range(2):
            for row_index in range(self.textbuffer.rows):
                self.epd.set_frame_memory(self.buf, row_index * font_height, 0,
                                          font_height, screen_width)

            # but only clear the screen once
            if i == 0:
                self.epd.display_frame()

    def clear(self):
        self.textbuffer.clear()
        self.debounce_update()
Example #6
0
 def setUp(self):
     self.tb = TextBuffer()
Example #7
0
 def __init__(self, cols=40, rows=4):
     self.textbuffer = TextBuffer(cols, rows)
Example #8
0
    def __init__(self, 
                content = "", 
                padding_x = 5, 
                padding_y = 2, 
                line_spacing = 5, 
                font_size = DEFAULT_FONT_SIZE, 
                text_color="#000000", 
                text_select_color="#000000", 
                background_select_color="#000000", ):
        gtk.EventBox.__init__(self)
        self.set_visible_window(False) # for transparent background
        self.__buffer = TextBuffer(content)
        self.padding_x = padding_x
        self.padding_y = padding_y
        self.line_spacing = line_spacing
        self.font_size = font_size
        self.text_color = text_color
        self.text_select_color = text_select_color
        self.background_select_color = background_select_color
        self.grab_focus_flag = False
        self.set_can_focus(True)
        self.drag_start_index = (0, 0)
        self.drag_end_index = (0, 0)
        self.offset_x = 0
        self.offset_y = 0
        self.double_click_flag = False
        self.left_click_flag = False
        
        self.im = gtk.IMMulticontext()
        self.im.connect("commit", lambda im, input_text: self.commit_entry(input_text))
        
        # Add keymap.
        self.keymap = {
                "Left" : self.move_to_left,
                "Right" : self.move_to_right,
                "Up" : self.move_up, 
                "Down" : self.move_down, 
                "Home" : self.move_to_start,
                "End" : self.move_to_end,
                "BackSpace" : self.backspace,
                "Delete" : self.press_delete,
                "S-Left" : self.select_to_left,
                "S-Right" : self.select_to_right,
                "S-Home" : self.select_to_start,
                "S-End" : self.select_to_end,
                "C-a" : self.select_all,
                "C-x" : self.cut_to_clipboard,
                "C-c" : self.copy_to_clipboard,
                "C-v" : self.paste_from_clipboard,
                "Return" : self.press_return,
                "PageDown" : self.press_page_down,
                "PageUp" : self.press_page_up }
        
        self.__buffer.connect("changed", self.redraw)

        self.connect("key-press-event", self.key_press_textview)
        self.connect("expose-event", self.expose_textview)
        self.connect("focus-in-event", self.focus_in_textview)
        self.connect("focus-out-event", self.focus_out_textview)
        self.connect("button-press-event", self.button_press_textview)
        self.connect("button-release-event", self.button_release_textview)
        self.connect("motion-notify-event", self.motion_notify_text_view)
Example #9
0
class TextView(gtk.EventBox):
    
    def __init__(self, 
                content = "", 
                padding_x = 5, 
                padding_y = 2, 
                line_spacing = 5, 
                font_size = DEFAULT_FONT_SIZE, 
                text_color="#000000", 
                text_select_color="#000000", 
                background_select_color="#000000", ):
        gtk.EventBox.__init__(self)
        self.set_visible_window(False) # for transparent background
        self.__buffer = TextBuffer(content)
        self.padding_x = padding_x
        self.padding_y = padding_y
        self.line_spacing = line_spacing
        self.font_size = font_size
        self.text_color = text_color
        self.text_select_color = text_select_color
        self.background_select_color = background_select_color
        self.grab_focus_flag = False
        self.set_can_focus(True)
        self.drag_start_index = (0, 0)
        self.drag_end_index = (0, 0)
        self.offset_x = 0
        self.offset_y = 0
        self.double_click_flag = False
        self.left_click_flag = False
        
        self.im = gtk.IMMulticontext()
        self.im.connect("commit", lambda im, input_text: self.commit_entry(input_text))
        
        # Add keymap.
        self.keymap = {
                "Left" : self.move_to_left,
                "Right" : self.move_to_right,
                "Up" : self.move_up, 
                "Down" : self.move_down, 
                "Home" : self.move_to_start,
                "End" : self.move_to_end,
                "BackSpace" : self.backspace,
                "Delete" : self.press_delete,
                "S-Left" : self.select_to_left,
                "S-Right" : self.select_to_right,
                "S-Home" : self.select_to_start,
                "S-End" : self.select_to_end,
                "C-a" : self.select_all,
                "C-x" : self.cut_to_clipboard,
                "C-c" : self.copy_to_clipboard,
                "C-v" : self.paste_from_clipboard,
                "Return" : self.press_return,
                "PageDown" : self.press_page_down,
                "PageUp" : self.press_page_up }
        
        self.__buffer.connect("changed", self.redraw)

        self.connect("key-press-event", self.key_press_textview)
        self.connect("expose-event", self.expose_textview)
        self.connect("focus-in-event", self.focus_in_textview)
        self.connect("focus-out-event", self.focus_out_textview)
        self.connect("button-press-event", self.button_press_textview)
        self.connect("button-release-event", self.button_release_textview)
        self.connect("motion-notify-event", self.motion_notify_text_view)

    def redraw(self, obj):
        self.queue_draw()

    def move_to_left(self):
        self.__buffer.move_cursor_left()
        self.queue_draw()
        
    
    def move_to_right(self):
        self.__buffer.move_cursor_right()
        self.queue_draw()
        
    def move_up(self):
        pass

    def move_down(self):
        pass

    def move_to_start(self):
        self.__buffer.move_cursor_to_line_start()
        self.queue_draw()
    
    def move_to_end(self):
        self.__buffer.move_cursor_to_line_end()
        self.queue_draw()
    
    def backspace(self):
        """when press backspace, delete one char"""
        ir = self.__buffer.get_iter_at_cursor()
        self.__buffer.backspace(ir)
        self.queue_draw()
    
    def press_delete(self):
        """when press delete, delete one char"""
        self.__buffer.reverse_backspace()
        self.queue_draw()
        
    def press_page_down(self):
        pass
    
    def press_page_up(self):
        pass
    
    def select_to_left(self):
        pass
    
    def select_to_right(self):
        pass
    
    def select_to_start(self):
        pass
    
    def select_to_end(self):
        pass
    
    def select_all(self):
        pass
    
    def cut_to_clipboard(self):
        cb = gtk.Clipboard()
        self.__buffer.cut_clipboard(cb)
        self.queue_draw()
    
    def copy_to_clipboard(self):
        cb = gtk.Clipboard()
        self.__buffer.copy_clipboard(cb)
    
    def paste_from_clipboard(self):
        cb = gtk.Clipboard()
        self.__buffer.paste_clipboard(cb)
        self.queue_draw()
    
    def press_return(self):
        self.__buffer.new_line_at_cursor()
        self.queue_draw()
    
    def motion_notify_text_view(self, widget, event):
        self.queue_draw()
        
    def button_press_textview(self, widget, event):
        '''Button press textview.'''
        # Get input focus.
        self.grab_focus()
        
        self.grab_focus_flag = True
        
        if is_left_button(event):
            self.left_click_flag = True
            self.left_click_coordindate = (event.x, event.y)
            
            self.drag_start_index = self.get_index_at_event(widget, event)

    def button_release_textview(self, widget, event):
        '''Button release textview.'''
        if not self.double_click_flag:
            self.drag_end_index = self.get_index_at_event(widget, event)    
            start_line_offset, start_line = self.drag_start_index
            end_line_offset, end_line = self.drag_end_index

            ir = self.__buffer.get_iter_at_line(start_line)
            ir2 = self.__buffer.get_iter_at_line(end_line)
            ir.set_line_offset(start_line_offset)
            ir2.set_line_offset(end_line_offset)

            self.__buffer.select_text(ir, ir2)

            ir, ir2 = self.__buffer.get_selection()

            print self.__buffer.get_slice(ir, ir2)

            self.queue_draw()

        self.double_click_flag = False
        self.left_click_flag = False

    def get_index_at_event(self, widget, event):
        '''Get index at event.'''
        cr = widget.window.cairo_create()
        context = pangocairo.CairoContext(cr)
        layout = context.create_layout()
        layout.set_font_description(pango.FontDescription("%s %s" % (DEFAULT_FONT, self.font_size)))
        layout.set_text(self.__buffer.get_text())
        text_width = self.get_content_width("x")
        text_height = get_content_size("好Height", self.font_size)[-1]
        index_x = 0
        index_y = 0
        event.x -= self.padding_x
        event.y -= self.padding_y
        for x in range(0, self.__buffer.get_line_count()):
            if text_height * x < event.y and event.y < text_height * (x + 1):
                index_y = x

        ir = self.__buffer.get_iter_at_line(index_y)

        for x in range(0, ir.get_chars_in_line()):
            if self.get_content_width(ir.get_line_text()[0:x]) < event.x and event.x < self.get_content_width(ir.get_line_text()[0:x+1]):
                index_x = x

        return (index_x, index_y)

    def focus_in_textview(self, widget, event):
        '''Callback for `focus-in-event` signal.'''
        self.grab_focus_flag = True

        # Focus in IMContext.
        self.im.set_client_window(widget.window)
        self.im.focus_in()

        self.queue_draw()
            
    def focus_out_textview(self, widget, event):
        '''Callback for `focus-out-event` signal.'''
        self.grab_focus_flag = False

        # Focus out IMContext.
        self.im.focus_out()

        self.queue_draw()
    
    def expose_textview(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        
        # draw text
        self.draw_text(cr, rect)
        
        # draw cursor
        if self.grab_focus_flag:
            self.draw_cursor(cr, rect)
        
        propagate_expose(widget, event)

        # resize widget for scrolledwindow-support
        max = 0
        for x in range(0, self.__buffer.get_line_count()):
             if max < self.get_content_width(self.__buffer.get_iter_at_line(x).get_line_text()):
                max = self.get_content_width(self.__buffer.get_iter_at_line(x).get_line_text())
        height = get_content_size("好Height", self.font_size)[-1] * (self.__buffer.get_iter_at_cursor().get_line())
        self.set_size_request(max + 10, height)
        
        return True

    def draw_background(self, cr, rect):
        pass
        
    def draw_text(self, cr, rect):
        x, y, w, h = rect.x, rect.y, rect.width, rect.height
        with cairo_state(cr):
            draw_x = x + self.padding_x
            draw_y = y + self.padding_y
            draw_width = w - self.padding_x * 2
            draw_height = h - self.padding_y * 2
            cr.rectangle(draw_x, draw_y, draw_width, draw_height)
            cr.clip()
            
            # pango context
            context = pangocairo.CairoContext(cr)
            
            # pango layout
            layout = context.create_layout()
            layout.set_font_description(pango.FontDescription("%s %s" % (DEFAULT_FONT, self.font_size)))
            
            text = self.__buffer.get_text()
            layout.set_text(text)
            
            (text_width, text_height) = layout.get_pixel_size()
            cr.move_to(x + self.padding_x , y + self.padding_y)
            
            cr.set_source_rgb(0,0,0)
            context.update_layout(layout)
            context.show_layout(layout)
            

    def __is_utf_8_text_in_line(self, line):
        decode_list = list(self.__buffer.get_iter_at_line(line).get_line_text().decode('utf-8'))
        for l in decode_list:
            if len(l.encode('utf-8')) != 1:
                # utf-8 character length >= 1
                return True

    def draw_cursor(self, cr, rect):
        x, y, w, h = rect.x, rect.y, rect.width, rect.height
        cursor_ir = self.__buffer.get_iter_at_cursor()
        left_str = cursor_ir.get_line_text()[0:cursor_ir.get_line_offset()]
        left_str_width = self.get_content_width(left_str)
        
        current_line = cursor_ir.get_line()

        line_offset = 0
        
        utf_8_height = get_content_size("好Height", self.font_size)[-1]
        no_utf_8_height = get_content_size("Height", self.font_size)[-1]

        for x in range(0, current_line):
            if self.__is_utf_8_text_in_line(x):
                line_offset += utf_8_height
            else:
                line_offset += no_utf_8_height

        temp_line_offset = 1 # solve the offset problem while adding lines
        

        cr.set_source_rgb(0,0,0)
        cr.rectangle(x + self.padding_x + left_str_width - temp_line_offset * current_line, y  + line_offset + utf_8_height - no_utf_8_height , 1, no_utf_8_height)
        cr.fill()
        
        
    def set_text(self, text):
        self.content = self.__parse_content(text)
        self.current_line = len(self.content.keys()) - 1 # currrent line index
        self.current_line_offset = len(self.content[self.current_line]) # offset in current line
        self.queue_draw()
        
    def key_press_textview(self, widget, event):
        input_method_filt = self.im.filter_keypress(event)
        if not input_method_filt:
            self.handle_key_event(event)
        return False
        
    def handle_key_event(self, event):
        '''Handle key event.'''
        key_name = get_keyevent_name(event)

        if self.keymap.has_key(key_name):
            self.keymap[key_name]()
            

    def get_content_width(self, content):
        '''Get content width.'''
        (content_width, content_height) = get_content_size(content, self.font_size)
        return content_width
    
    def commit_entry(self, input_text):
        self.__buffer.insert_text_at_cursor(input_text)
        self.queue_draw()
        
    def get_utf8_string(self, content, index):
        '''Get utf8 string.'''
        try:
            return list(content.decode('utf-8'))[index].encode('utf-8')
        except Exception, e:
            print "get_utf8_string got error: %s" % (e)
            return ""