vroland / epdiy

EPDiy is a driver board for affordable e-Paper (or E-ink) displays.
https://vroland.github.io/epdiy-hardware/
GNU Lesser General Public License v3.0
1.25k stars 178 forks source link

epd_write_string confusion #328

Open holgerlembke opened 1 week ago

holgerlembke commented 1 week ago

I want to draw some text with a box around it. It does not give the result I assume.... I assume it is /me missing something. But what?

void BuildStatusLine() {
  const EpdFont* font = &FiraSans_12;

  String status = "hallo";

  const int margin = 2;

  EpdRect r = epd_get_string_rect(font, status.c_str(), 0, 0, margin, &epaperfont_props);

  epd_draw_rect(r, black, epaperFrameBuffer);

  r.x += margin;
  r.y += margin;

  epd_write_string(font, status.c_str(), &r.x, &r.y, epaperFrameBuffer, &epaperfont_props);
}

I get this result:

grafik

https://epdiy.readthedocs.io/en/latest/api.html#highlevel-api says that epd_get_string_rect gives the left/top corner in .x and .y.

If I change the code (and the font, but that does not matter) to

void BuildStatusLine() {
  const EpdFont* font = &FiraSans_20;

  String status = "hallog";

  const int margin = 2;

  EpdRect r = epd_get_string_rect(font, status.c_str(), 0, 0, margin, &epaperfont_props);

  epd_draw_rect(r, black, epaperFrameBuffer);

  r.x += margin;
  r.y += r.height;
  r.y -= margin;

  epd_write_string(font, status.c_str(), &r.x, &r.y, epaperFrameBuffer, &epaperfont_props);
}

I get

grafik

So to /me it looks like epd_get_string_rect does not give anything that can be used by epd_write_string directly.

What do I miss here?

martinberlin commented 1 week ago

If I see this correctly, from the top of my head, the thing is that epd_write_string x,y start is the lower left corner. Need to try this myself. But if you try for example making a small gray circle at x,y:

epd_fill_circle(x, y, 4, 125, epaperFrameBuffer);

And then drawing the font you can check what is the starting point to draw the font. That would explain what is happening here.

holgerlembke commented 1 week ago

All nice and good. But how to solve the task "draw a rectangle around a given text"?

If I have a box with x/y (top/left corner), calc the bounding box and and the height to top (y+=height), I should be at the bottom.

That seems not to work. /me confused.

martinberlin commented 3 days ago

Holger what you can easily make here is a helper function where you can pass the Font and x, y origin of the text and this function will draw both the text and the rectangle for you.

I can help you to do this but first would be nice if you try it yourself.

holgerlembke commented 3 days ago

Easily? Looks like my skills are overrated... All I get is that:

grafik

Example is in https://github.com/holgerlembke/epdiy/tree/main/examples/Basics/F_Text_in_Rectangle

I have no idea what to do.

martinberlin commented 3 days ago

Can’t you just make a function to offset that rectangle X pixels down depending on the font size? Will take a look

holgerlembke commented 3 days ago

I can make a lot of things.

But I really want to understand what happens here. If it is a bug, if I'm stupid or what else.

martinberlin commented 3 days ago

Try this:

void Text_In_Rectangle_Hlpr(int x, int y, char * text) {
  const EpdFont* font = &FiraSans_20;
  EpdFontProperties font_props = epd_font_properties_default();
  const int margin = 2;

  printf("Attempt to write a font at x:%d y:%d\n\n", x, y);
  EpdRect r = epd_get_string_rect(font, text, x, y, margin, &font_props);

  // Offset EpdRect to half y size of the font - a margin (does not have to be the same)
  r.y -= font->advance_y - (margin*2);
  epd_draw_rect(r, 0, fb);
  epd_write_string(font, text, &x, &y, fb, &font_props);
}

It's just an example so feel free to copy only relevant parts. You are doing wrong the write_string in my opinion. I would also directly pass the Font to the function so then you can reuse it for different fonts and can adapt to the size. Note that I'm using the advance_y property of the font struct itself to calculate the offset of the rectangle.

Changing topic @vroland I feel that many users have a hard time trying to draw stuff with epdiy. Maybe for some users it will would be easier that I make a C++ wrapper around a known library like Adafruit GFX. And then you can use their guides and documentation to draw easy stuff the way you want. But I like more the way epdiy Fonts work of course. It's just that for many in my opinion the way it is to draw something more or less complex now, is quite hard to grasp. That's of course my humble opinion after trying to do support here.

holgerlembke commented 3 days ago

@martinberlin Thanks.

A class-wrapper would be nice. I could do it... It needs some more functions, I miss a rectangle with round edges, I have it on my list...

Here the problem was/is the missing bits of information in https://epdiy.readthedocs.io/en/latest/api.html or source code and my unwillingness to dig into it. That is why I build some new basic examples. This will go into it.

Do I have to call epd_font_properties_default after assigning a font?

My only change to epdiy is EpdRect makeEpdRect(int x, int y, int w, int h);, I do not really like to change stuff in "no my libs".

So, next example is a clock. grafik

martinberlin commented 3 days ago

Do I have to call epd_font_properties_default after assigning a font?

no. You can just make font_props local if it’s the same for all fonts and just pass it around. The fonts part I like but the code itself to print a single text is a bit too verbose.