OLED Library Writer, Clear to end of line

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
stanely
Posts: 40
Joined: Fri Jan 17, 2020 5:19 am
Location: Ohio, USA

OLED Library Writer, Clear to end of line

Post by stanely » Fri Jan 24, 2020 6:28 am

I'm using Peter Hinch's (@ pythoncoder) Writer library. It is an excellent tool and is making my programming much more enjoyable and easier. One of the things I'm doing is updating info on single lines. This works well, but I'm struggling to clear the display to the end of line because sometimes there's prior info that needs erased. I've got a workaround where I set:

Writer.set_clip(True, True, False)

So the writer is set to clip a line, and I send a bunch of extra spaces to overwrite what might be there from a previous write. Is there a better way to do this automatically?

User avatar
pythoncoder
Posts: 4232
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: OLED Library Writer, Clear to end of line

Post by pythoncoder » Sat Jan 25, 2020 7:12 am

I think this is the only way to do it. I guess a useful enhancement would be to implement a clear_line() method which would clear the line from the current insertion point to the end. This could be called before or after writing a string. However the Writer class is intended to be minimal and I have various options which build on this.

You could try nano-gui which builds on the Writer. This implements a Label class which can display variable length text in a field of defined size.
Peter Hinch

stanely
Posts: 40
Joined: Fri Jan 17, 2020 5:19 am
Location: Ohio, USA

Re: OLED Library Writer, Clear to end of line

Post by stanely » Tue Jan 28, 2020 8:21 pm

I came up with another way to clear to end of line and am wondering if it will be faster than what I'm doing now. My ESP32 (Heltec WiFi Kit) implementation has a reset pin on the OLED, and I can clear the whole thing by flipping that pin. The Writer documentation talks about blitting, so I'm guessing when I do an ssd.show() only that line is written.

Is it faster to reset the screen and rewrite the whole thing or send a bunch of extra blanks on just one line that gets clipped? My screen has one line of large font and 2 lines of small font.

User avatar
pythoncoder
Posts: 4232
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: OLED Library Writer, Clear to end of line

Post by pythoncoder » Wed Jan 29, 2020 10:27 am

The GUI library I mentioned clears Label fields before rendering text to them. It does this by drawing a filled rectangle of the correct size to the area.
Peter Hinch

stanely
Posts: 40
Joined: Fri Jan 17, 2020 5:19 am
Location: Ohio, USA

Re: OLED Library Writer, Clear to end of line

Post by stanely » Sat Feb 29, 2020 8:54 pm

I ran into a case where I'm unable to clear fragments of prior text on a Writer line by appending blanks to the new text. This happens when the rightmost column has pixels. I tried but couldn't figure out how to use Label with my Writer class.

I was able to clear the line by first writing blanks to the line. I don't exactly know why that works and why appending blanks doesn't. I think it has to do with how Writer handles excess characters when "CLIP" is set. Here's how I clear the line before writing to it...

Code: Select all

# Create Writer instance.
wri = Writer(ssd, font, verbose=False)
wri.set_clip(True, True, False)             # Clip is on, wrap is off.

# Create blank string to erase display line to eol.
blank_width = wri._charlen(' ')    # Width of a blank
x = blank_width      # Start with one blank width.
clr_eol = ' '
while x < SCREEN_WIDTH:
	clr_eol += ' '
	x += blank_width
The writing of a new Writer line to the display is preceded with a blanking line like this,

Code: Select all

wri.set_textpos(ssd, y, 0)
wri.printstring(ssd, clr_eol)
wri.set_textpos(ssd, y, 0)
wri.printstring(ssd, new_text)
ssd.show()
This seems to work, but it might only be working for the blank width and screen width combination that I happen to be using.

User avatar
pythoncoder
Posts: 4232
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: OLED Library Writer, Clear to end of line

Post by pythoncoder » Sun Mar 01, 2020 12:03 pm

The Label class is part of nano-gui and not intended to be used with Writer. The latter is a minimal class for rendering text whereas nano-gui is a complete (nano) GUI library.

Writing spaces to clear a field can only be expected to work with fixed-pitch fonts. With variable-pitch fonts you inevitably get involved with font metrics.

The choices as I see them are:
  1. Use nano-gui in its entirety to write data to Label instances.
  2. Create your own Label type class, let's call it Field. Field would use Writer to render text to a defined geometric region. Prior to rendering, Field's write method would clear the text area by drawing a filled rectangle of the correct size. The height can be determined from the font's height method, and the width from your Field control's width. You can ensure your text doesn't overflow the field by calculating its width in pixels (Writer.stringlen()) and truncating.
This is basically emulating what Label does.
Peter Hinch

stanely
Posts: 40
Joined: Fri Jan 17, 2020 5:19 am
Location: Ohio, USA

Re: OLED Library Writer, Clear to end of line

Post by stanely » Sun Mar 01, 2020 1:29 pm

pythoncoder wrote:
Sun Mar 01, 2020 12:03 pm
The choices as I see them are:
  1. Use nano-gui in its entirety to write data to Label instances.
  2. Create your own Label type class, let's call it Field. Field would use Writer to render text to a defined geometric region. Prior to rendering, Field's write method would clear the text area by drawing a filled rectangle of the correct size. The height can be determined from the font's height method, and the width from your Field control's width. You can ensure your text doesn't overflow the field by calculating its width in pixels (Writer.stringlen()) and truncating.
Thanks, that makes more sense.

It looks like anyway I go, I get involved with font metrics. That's why I used the width of a blank to compute the number of blanks to write with Writer.

The way I understand 'Label' is that it takes (x, y, text), calculates the field size, clears the field, and writes the text. But I need to clear the entire line. So the field that 'Label' needs to clear may be bigger than the text I'm sending. That means I first have to write a full-line of blanks, and then send the text to be written. That's kind of what I'm doing now with 'Writer'.

Depending on the font that I'm using, there's no guarantee an integer number of my font's blanks divide the screen exactly. So I'm still stuck with what to do at the right margin. (I think there's a small bug in Writer when writing the last right margin character in clip/no-wrap mode. That's why I think writing a line of blanks with one extra seems to be working.)

Is there a way for me to reach into Writer's framebuf and clear an area directly? I know my font's max height and the screen width, so that's easy arithmetic.

User avatar
pythoncoder
Posts: 4232
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: OLED Library Writer, Clear to end of line

Post by pythoncoder » Sun Mar 01, 2020 1:34 pm

stanely wrote:
Sun Mar 01, 2020 1:29 pm
...
Is there a way for me to reach into Writer's framebuf and clear an area directly? I know my font's max height and the screen width, so that's easy arithmetic.
OK, you've got the location and the dimensions. Presumably your display driver has a method for drawing a filled rectangle. Use that before rendering the text. That's what the Label class does.
Peter Hinch

stanely
Posts: 40
Joined: Fri Jan 17, 2020 5:19 am
Location: Ohio, USA

Re: OLED Library Writer, Clear to end of line

Post by stanely » Sun Mar 01, 2020 3:25 pm

There is no such method. I think that's done by a framebuf method. I don't yet understand framebuf and how screen pixels map to framebuf.

stanely
Posts: 40
Joined: Fri Jan 17, 2020 5:19 am
Location: Ohio, USA

Re: OLED Library Writer, Clear to end of line

Post by stanely » Sun Mar 01, 2020 11:49 pm

Peter, I think I just hacked a 'clear_to_eol()' method into 'writer.py'! I did it by creating a single column glyph of b'\x00' bits. The method writes this glyph from current column position to the end of screen width. Inverted display is supported just like for _printchar(). In fact, I mostly copied the _printchar() method to do this. I had to add a constant to _init_(). Here's the code...

Code: Select all

    def __init__(self, device, font, verbose=True):
	#.... all the other code just like before and at the end,
	# added a constant which is a one column blank glyph.
        self.blank_column = self.font.height() * b'\x00'
And then here is the 'clear_to_eol()' method...

Code: Select all

    # Clear to end of line by writing a column of off pixels.  Doesn't change current position.
    def clear_to_eol(self, invert=False):
        s = self._getstate()
        buf = bytearray(self.blank_column)
        if invert:
            for i, v in enumerate(buf):
                buf[i] = 0xFF & ~ v
        fbc = framebuf.FrameBuffer(buf, 1, self.char_height, self.map)
        for i in range(s.text_col, self.device.width):
            self.device.blit(fbc, i, s.text_row)
The best thing is that this method can be called after the current line was written, and it simply fills the remaining text line columns with blanks. So the entire line isn't cleared first... just what might be left over from a previous write.

This was a lot of hair pulling for 10 lines of code. :)

Post Reply