@@ -44,6 +44,7 @@ uint8_t font_transparent; // if not 0 draw fonts transparent | |||
uint8_t font_forceFixed; // if not zero force drawing proportional fonts with fixed width | |||
uint8_t font_buffered_char; | |||
uint8_t font_line_space; // additional spacing between text lines; added to font height | |||
uint8_t font_x_space; // additional spacing between characters in x axis | |||
uint8_t text_wrap; // if not 0 wrap long text to the new line, else clip | |||
color_t _fg; // current foreground color for fonts | |||
color_t _bg; // current background for non transparent fonts | |||
@@ -1732,10 +1733,10 @@ int EPD_getStringWidth(char* str) | |||
char* tempStrptr = str; | |||
while (*tempStrptr != 0) { | |||
if (getCharPtr(*tempStrptr++)) { | |||
strWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + 1); | |||
strWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + font_x_space); | |||
} | |||
} | |||
strWidth--; | |||
strWidth -= font_x_space; | |||
} | |||
return strWidth; | |||
} | |||
@@ -1980,7 +1981,7 @@ void EPD_print(char *st, int x, int y) { | |||
// Let's print the character | |||
if (cfont.x_size == 0) { | |||
// == proportional font | |||
if (font_rotate == 0) EPD_X += printProportionalChar( EPD_X, EPD_Y) + 1; | |||
if (font_rotate == 0) EPD_X += printProportionalChar( EPD_X, EPD_Y) + font_x_space; | |||
else { | |||
// rotated proportional font | |||
offset += rotatePropChar(x, y, offset); | |||
@@ -45,6 +45,7 @@ extern uint8_t font_transparent; // if not 0 draw fonts transparent | |||
extern uint8_t font_forceFixed; // if not zero force drawing proportional fonts with fixed width | |||
extern uint8_t font_buffered_char; | |||
extern uint8_t font_line_space; // additional spacing between text lines; added to font height | |||
extern uint8_t font_x_space; // additional spacing between characters in x axis | |||
extern uint8_t text_wrap; // if not 0 wrap long text to the new line, else clip | |||
extern color_t _fg; // current foreground color for fonts | |||
extern color_t _bg; // current background for non transparent fonts | |||
@@ -7,6 +7,7 @@ class Page | |||
public: | |||
Page(); | |||
size_t start; | |||
char* text; | |||
size_t len; | |||
@@ -5,7 +5,8 @@ | |||
#include "esp_log.h" | |||
static const char *TAG = "PagePrinter"; | |||
int font = DEJAVU18_FONT;//DEFAULT_FONT; | |||
//int pageFont = DEFAULT_FONT; | |||
int pageFont = DEJAVU18_FONT; | |||
PagePrinter::PagePrinter() | |||
{} | |||
@@ -19,7 +20,7 @@ void PagePrinter::print(Page* page) | |||
if (page->len == 0) { | |||
return; | |||
} | |||
EPD_setFont(font, NULL); | |||
EPD_setFont(pageFont, NULL); | |||
text_wrap = 1; | |||
EPD_print(page->text, 0, 0); | |||
//EPD_UpdateScreen(); | |||
@@ -6,6 +6,4 @@ public: | |||
PagePrinter(); | |||
void print(Page* page); | |||
private: | |||
}; |
@@ -0,0 +1,48 @@ | |||
#include "PageSettingsProvider.h" | |||
#include "EPD.h" | |||
#include "EPDspi.h" // TODO: remove after display config is extracted | |||
int PageSettingsProvider::getWidth() | |||
{ | |||
return EPD_DISPLAY_WIDTH; | |||
} | |||
int PageSettingsProvider::getHeight() | |||
{ | |||
return EPD_DISPLAY_HEIGHT; | |||
} | |||
int PageSettingsProvider::getCharWidth(char c) | |||
{ | |||
char txt[2] = { c, 0x00 }; | |||
return this->getStringWidth(txt); | |||
} | |||
extern int pageFont; | |||
void activatePageFont() | |||
{ | |||
EPD_setFont(pageFont, NULL); // TODO: hack to get the same font as the printer | |||
} | |||
int PageSettingsProvider::getStringWidth(char* string) | |||
{ | |||
activatePageFont(); | |||
int ret = EPD_getStringWidth(string); | |||
return ret; | |||
} | |||
int PageSettingsProvider::getCharSpace() | |||
{ | |||
return font_x_space; | |||
} | |||
int PageSettingsProvider::getLineHeight() | |||
{ | |||
activatePageFont(); | |||
return EPD_getfontheight(); | |||
} | |||
int PageSettingsProvider::getLineSpace() | |||
{ | |||
return font_line_space; | |||
} |
@@ -0,0 +1,12 @@ | |||
class PageSettingsProvider | |||
{ | |||
public: | |||
int getWidth(); | |||
int getHeight(); | |||
int getCharWidth(char c); | |||
int getStringWidth(char* string); | |||
int getCharSpace(); | |||
int getLineHeight(); | |||
int getLineSpace(); | |||
}; |
@@ -32,7 +32,7 @@ size_t TextReader::read(long pos, char* text, size_t len) | |||
fseek(this->f, pos, SEEK_SET); | |||
size_t read = fread(text, 1, len, this->f); | |||
if (read > 0) { | |||
ESP_LOGI(TAG, "Read content: %s", text); | |||
//ESP_LOGI(TAG, "Read content: %s", text); | |||
} else { | |||
ESP_LOGI(TAG, "End of file. Closing."); | |||
fclose(this->f); | |||
@@ -1,27 +1,38 @@ | |||
#include <string.h> | |||
#include "Typesetter.h" | |||
#include "esp_log.h" | |||
static const char *TAG = "Typesetter"; | |||
Typesetter::Typesetter() | |||
{} | |||
{ | |||
this->pageSettingsProvider = new PageSettingsProvider(); // TODO: make it a param | |||
} | |||
Page* Typesetter::preparePage(char* text, size_t len) | |||
Typesetter::~Typesetter() | |||
{ | |||
delete this->pageSettingsProvider; | |||
} | |||
static Page* extractPage(char* text, size_t len) | |||
{ | |||
Page* page = new Page; | |||
page->text = new char[len+1]; | |||
memcpy(page->text, text, len); | |||
page->text[len] = 0; | |||
page->len = len; | |||
ESP_LOGI(TAG, "Extracted page (%d bytes):\n%s\n----", page->len, page->text); | |||
return page; | |||
} | |||
Page* Typesetter::preparePage(char* text, size_t len) | |||
{ | |||
return this->preparePageInternal(text, len, 0); | |||
} | |||
Page* Typesetter::preparePreviousPage(char* text, size_t len) | |||
{ | |||
Page* page = new Page; | |||
page->text = new char[len+1]; | |||
memcpy(page->text, text, len); | |||
page->text[len] = 0; | |||
page->len = len; | |||
return page; | |||
return this->preparePageInternal(text, len, 1); | |||
} | |||
void Typesetter::destroyPage(Page* page) | |||
@@ -32,3 +43,40 @@ void Typesetter::destroyPage(Page* page) | |||
delete page->text; | |||
delete page; | |||
} | |||
Page* Typesetter::preparePageInternal(char* text, size_t len, int reverse) | |||
{ | |||
int page_width = this->pageSettingsProvider->getWidth(); | |||
int page_height = this->pageSettingsProvider->getHeight(); | |||
int line_height = this->pageSettingsProvider->getLineHeight() | |||
+ this->pageSettingsProvider->getLineSpace(); | |||
int line_count = page_height / line_height; | |||
char buf[len+1]; | |||
memset(buf, 0, len+1); | |||
int line_start = 0; | |||
ESP_LOGI(TAG, " === Typesetting%s page === ", reverse ? " reversed" : ""); | |||
for (int line = 0; line < line_count && line_start < len; line++) { | |||
int i; | |||
for (i = line_start; i < len; i++) { | |||
buf[i] = text[reverse ? (len - i) : (i)]; | |||
if (buf[i] == '\n') { | |||
break; | |||
} | |||
int line_width = this->pageSettingsProvider->getStringWidth(&buf[line_start]); | |||
if (line_width > page_width) { | |||
// backtrack | |||
buf[i] = 0; | |||
i--; | |||
break; | |||
} | |||
} | |||
ESP_LOGI(TAG, "Line %d | %s", line, &buf[line_start]); | |||
//ESP_LOGI(TAG, "Line %d [%04d:%04d] | %s | %03d / %03d", line, line_start, i, &buf[line_start], | |||
// this->pageSettingsProvider->getStringWidth(&buf[line_start]), page_width); | |||
line_start = i + 1; | |||
} | |||
return extractPage(text, line_start); | |||
} |
@@ -1,12 +1,20 @@ | |||
#include <stdlib.h> | |||
#include "Page.h" | |||
#include "PageSettingsProvider.h" | |||
class Typesetter | |||
{ | |||
public: | |||
Typesetter(); | |||
~Typesetter(); | |||
Page* preparePage(char* text, size_t len); | |||
Page* preparePreviousPage(char* text, size_t len); | |||
void destroyPage(Page* page); | |||
private: | |||
Page* preparePageInternal(char* text, size_t len, int direction); | |||
PageSettingsProvider* pageSettingsProvider; // TODO: expose so it may be changed | |||
}; | |||
@@ -70,11 +70,20 @@ extern "C" void app_main() | |||
if (textReader != NULL) { | |||
if (pageCurrent == NULL) { | |||
size_t read = textReader->read(bookmark, text, sizeof(text)); | |||
pageCurrent = typesetter.preparePage(text, sizeof(text)); | |||
pageCurrent = typesetter.preparePage(text, read); | |||
pageCurrent->start = bookmark; | |||
} | |||
if (pageLast == NULL) { | |||
size_t read = textReader->read(bookmark - sizeof(text), text, sizeof(text)); | |||
pageLast = typesetter.preparePreviousPage(text, sizeof(text)); | |||
// align with the start? | |||
if (bookmark < sizeof(text)) { | |||
size_t read = textReader->read(0, text, sizeof(text)); | |||
pageLast = typesetter.preparePage(text, read); | |||
pageLast->start = 0; | |||
} else { | |||
size_t read = textReader->read((bookmark - sizeof(text)), text, sizeof(text)); | |||
pageLast = typesetter.preparePreviousPage(text, read); | |||
pageLast->start = bookmark - pageLast->len; | |||
} | |||
} | |||
} else { | |||
typesetter.destroyPage(pageCurrent); | |||
@@ -97,7 +106,8 @@ extern "C" void app_main() | |||
if (buttons_pressed_plus()) { | |||
ESP_LOGI(TAG, "Turn page PLUS."); | |||
if (pageCurrent != NULL) { | |||
bookmark += pageCurrent->len; | |||
bookmark = pageCurrent->start + pageCurrent->len; | |||
// TODO: limit bookmark to file size | |||
typesetter.destroyPage(pageLast); | |||
pageLast = pageCurrent; | |||
pageCurrent = NULL; | |||
@@ -109,7 +119,7 @@ extern "C" void app_main() | |||
if (buttons_pressed_minus()) { | |||
ESP_LOGI(TAG, "Turn page MINUS."); | |||
if (pageLast != NULL) { | |||
bookmark -= pageLast->len; | |||
bookmark = pageLast->start; | |||
typesetter.destroyPage(pageCurrent); | |||
pageCurrent = pageLast; | |||
pageLast = NULL; | |||