diff --git a/sources/core/apps/text-reader/res/text-reader.json b/sources/core/apps/text-reader/res/text-reader.json index 38471d1ed..92a831f89 100644 --- a/sources/core/apps/text-reader/res/text-reader.json +++ b/sources/core/apps/text-reader/res/text-reader.json @@ -2,5 +2,6 @@ "font_path": "/usr/bin/res/text-reader/default_font.ttf", "font_bitmap_path": "/usr/bin/res/text-reader/default_bitmap_font.pcf", "background_color": 4277049, + "background_count_color": 592137, "wallpaper_path": "/usr/bin/res/text-reader/default_wallpaper.jpg" } diff --git a/sources/core/apps/text-reader/source/core/core.c b/sources/core/apps/text-reader/source/core/core.c index a5c138b6a..e87e6d4a2 100644 --- a/sources/core/apps/text-reader/source/core/core.c +++ b/sources/core/apps/text-reader/source/core/core.c @@ -37,7 +37,8 @@ #define TEXT_COLOR (0xffffff) #define INFO_SIZE (16) #define WRITE_AREA_MARGIN (5) -#define CURSOR_SHOW_DURATION_MS (500) +#define LINE_COUNT_MAX_CHAR (4) +#define LINE_COUNT_WIDTH (FONT_WIDTH * LINE_COUNT_MAX_CHAR + WRITE_AREA_MARGIN * 3) kfont_t font; @@ -46,21 +47,20 @@ kframebuffer_t fb; struct fb_fix_screeninfo fix_screeninfo; struct fb_var_screeninfo var_screeninfo; +kframebuffer_t* text_framebuffer = NULL; + char* font_path = NULL; char* wallpaper_path = NULL; char* font_bitmap_path = NULL; color_t background_color = 0; +color_t background_count_color = 0; -size_t text_current_line = 0; -size_t text_lines_count = 0; size_t text_file_size = 0; size_t text_index_start = 0; -size_t text_index_cursor = 0; char* text_buffer = NULL; FILE* text_file = NULL; -uint32_t cursor_x = 0; -uint32_t cursor_y = 0; +size_t copy_offset = 0; uint8_t* font_bitmap_data = NULL; size_t font_bitmap_file_size = 0; @@ -73,18 +73,24 @@ cJSON* font_path_json = NULL; cJSON* font_bitmap_path_json = NULL; cJSON* wallpaper_path_json = NULL; cJSON* background_color_json = NULL; +cJSON* background_count_color_json = NULL; uint32_t char_row_count = 0; uint32_t char_col_count = 0; -void bitmap_setchar(uint16_t cx_ppos, uint16_t cy_ppos, char c, color_t fg_color){ +uint32_t write_area_x = 0; +uint32_t write_area_y = 0; +uint32_t write_area_width = 0; +uint32_t write_area_height = 0; + +void bitmap_setchar(kframebuffer_t* framebuffer, uint32_t cx_ppos, uint32_t cy_ppos, char c, color_t fg_color){ uint8_t* glyph = &font_bitmap_data[c*((FONT_WIDTH*FONT_HEIGHT)/8)]; - for(uint16_t y = 0; y < FONT_HEIGHT; y++) { - for(uint16_t x = 0; x < FONT_WIDTH; x++) { + for(uint32_t y = 0; y < FONT_HEIGHT; y++) { + for(uint32_t x = 0; x < FONT_WIDTH; x++) { if(glyph[y] & (1 << FONT_WIDTH - x)) { - put_pixel(&fb, cx_ppos + x, cy_ppos, fg_color); + put_pixel(framebuffer, cx_ppos + x, cy_ppos, fg_color); } } cy_ppos++; @@ -102,6 +108,27 @@ void draw_frame(){ write(fb_fd, fb.buffer, fb.size); } +void scroll_down(int i){ + for(int a = 0; a < i; a++){ + if(copy_offset > text_framebuffer->pitch * FONT_HEIGHT){ + copy_offset -= text_framebuffer->pitch * FONT_HEIGHT; + }else{ + copy_offset = 0; + } + } +} + + +void scroll_up(int i){ + for(int a = 0; a < i; a++){ + if((text_framebuffer->size - copy_offset) > (write_area_height * text_framebuffer->pitch)){ + copy_offset += text_framebuffer->pitch * FONT_HEIGHT; + }else{ + copy_offset = text_framebuffer->size - (write_area_height * text_framebuffer->pitch); + } + } +} + int get_key(int* pressed, uint64_t* key){ int64_t buffer; if(read(fb_fd, &buffer, 1) > 0){ @@ -116,24 +143,73 @@ int get_key(int* pressed, uint64_t* key){ return 0; } -char* get_file_ext(char* name) { - char* dot = strrchr(name, '.'); - if(!dot || dot == name) return ""; - return dot + 1; -} +int get_input(){ + static bool arrow_pressed = false; + static bool wait_release = false; + static bool wait_release_up = false; + static bool wait_release_down = false; + static bool wait_release_right = false; + static bool wait_release_left = false; + + int pressed = 0; + uint64_t key = 0; + int ret = get_key(&pressed, &key); -int wait_escape(){ - int pressed; - uint64_t key; + if(ret){ + if(key == 96 && !arrow_pressed){ + arrow_pressed = true; + }else{ + if(arrow_pressed && pressed){ + if(key == 72 && !wait_release_up){ + // up + wait_release_up = true; + scroll_down(1); + }else if(key == 80 && !wait_release_down){ + // down + wait_release_down = true; + scroll_up(1); + }else if(key == 77 && !wait_release_right){ + // right + wait_release_right = true; + scroll_up(char_col_count); + }else if(key == 75 && !wait_release_left){ + // left + wait_release_left = true; + scroll_down(char_col_count); + } - if(get_key(&pressed, &key)){ - if(pressed && key == 1){ - return 1; + arrow_pressed = false; + }else if(arrow_pressed && !pressed){ + if(key == 72 && wait_release_up){ + // up + wait_release_up = false; + }else if(key == 80 && wait_release_down){ + // down + wait_release_down = false; + }else if(key == 77 && wait_release_right){ + // down + wait_release_right = false; + }else if(key == 75 && wait_release_left){ + // down + wait_release_left = false; + } + arrow_pressed = false; + }else if(key == 1 && pressed){ + // exit + return 1; + } } } return 0; } + +char* get_file_ext(char* name) { + char* dot = strrchr(name, '.'); + if(!dot || dot == name) return ""; + return dot + 1; +} + int load_fb(){ fb_fd = open("/dev/fb0", O_RDWR); @@ -235,6 +311,18 @@ int load_json(){ printf("Error: Unable to parse the file : /usr/bin/res/text-reader/text-reader.json\n"); return EXIT_FAILURE; } + + background_count_color_json = cJSON_GetObjectItem(json_root, "background_count_color"); + if(cJSON_IsNumber(background_count_color_json)){ + background_count_color = background_count_color_json->valueint; + }else{ + free(json_buffer); + + fclose(json_file); + + printf("Error: Unable to parse the file : /usr/bin/res/text-reader/text-reader.json\n"); + return EXIT_FAILURE; + } }else{ free(json_buffer); @@ -301,15 +389,128 @@ int load_text_file(char* path){ fread(text_buffer, text_file_size, 1, text_file); fclose(text_file); - char* c = text_buffer; + return EXIT_SUCCESS; +} + +uint32_t get_buffer_height(){ + char* c = &text_buffer[text_index_start]; + uint32_t cx_pos = 0; + uint32_t cy_pos = 0; + + uint32_t col_count = 0; + uint32_t row_count = 0; + uint32_t c_count = 0; while(*c){ if(*c == '\n'){ - text_lines_count++; + row_count = 0; + cx_pos = 0; + cy_pos += FONT_HEIGHT; + col_count++; + }else if(*c == '\t'){ + row_count++; + cx_pos += FONT_WIDTH; + + row_count -= row_count % TAB_CHAR_COUNT; + row_count += TAB_CHAR_COUNT; + cx_pos -= cx_pos % (TAB_CHAR_COUNT * FONT_WIDTH); + cx_pos += TAB_CHAR_COUNT * FONT_WIDTH; + }else{ + if(row_count >= char_row_count){ + row_count = 0; + cx_pos = 0; + cy_pos += FONT_HEIGHT; + col_count++; + if(col_count >= char_col_count){ + break; + } + } + + cx_pos += FONT_WIDTH; + row_count++; } + + c_count++; c++; } - return EXIT_SUCCESS; + return cy_pos; +} + +kframebuffer_t* load_buffer(){ + kframebuffer_t* framebuffer = malloc(sizeof(kframebuffer_t)); + framebuffer->bpp = fb.bpp; + framebuffer->btpp = fb.btpp; + framebuffer->width = write_area_width; + framebuffer->height = get_buffer_height(); + framebuffer->pitch = framebuffer->width * framebuffer->btpp; + framebuffer->size = framebuffer->pitch * framebuffer->height; + framebuffer->buffer = malloc(framebuffer->size); + + draw_rectangle(framebuffer, LINE_COUNT_WIDTH, 0, framebuffer->width - LINE_COUNT_WIDTH, framebuffer->height, background_color); + draw_rectangle(framebuffer, 0, 0, LINE_COUNT_WIDTH, framebuffer->height, background_count_color); + + char* c = &text_buffer[text_index_start]; + uint32_t cx_pos = LINE_COUNT_WIDTH; + uint32_t cy_pos = 0; + + uint32_t col_count = 0; + uint32_t row_count = 0; + uint32_t c_count = 0; + + { + char* line_count_str = NULL; + assert(asprintf(&line_count_str, "%04d", col_count + 1) >= 0); + uint32_t line_count_x = 0; + while(*line_count_str){ + line_count_x += FONT_WIDTH; + bitmap_setchar(framebuffer, line_count_x, cy_pos, *line_count_str, TEXT_COLOR); + line_count_str++; + } + } + + while(*c){ + if(*c == '\n'){ + row_count = 0; + cx_pos = LINE_COUNT_WIDTH; + cy_pos += FONT_HEIGHT; + col_count++; + char* line_count_str = NULL; + assert(asprintf(&line_count_str, "%04d", col_count + 1) >= 0); + uint32_t line_count_x = 0; + while(*line_count_str){ + line_count_x += FONT_WIDTH; + bitmap_setchar(framebuffer, line_count_x, cy_pos, *line_count_str, TEXT_COLOR); + line_count_str++; + } + }else if(*c == '\t'){ + row_count++; + cx_pos += FONT_WIDTH; + + row_count -= row_count % TAB_CHAR_COUNT; + row_count += TAB_CHAR_COUNT; + cx_pos -= (cx_pos - LINE_COUNT_WIDTH) % (TAB_CHAR_COUNT * FONT_WIDTH); + cx_pos += TAB_CHAR_COUNT * FONT_WIDTH; + }else{ + if(row_count >= char_row_count){ + row_count = 0; + cx_pos = LINE_COUNT_WIDTH; + cy_pos += FONT_HEIGHT; + col_count++; + if(col_count >= char_col_count){ + break; + } + } + + bitmap_setchar(framebuffer, cx_pos, cy_pos, *c, TEXT_COLOR); + cx_pos += FONT_WIDTH; + row_count++; + } + + c_count++; + c++; + } + + return framebuffer; } int main(int argc, char* argv[]){ @@ -369,10 +570,10 @@ int main(int argc, char* argv[]){ set_pen_size(font, HEADER_SIZE); - uint32_t write_area_x = WIDTH_MARGIN; - uint32_t write_area_y = HEADER_HEIGHT + MARGIN_HEIGHT; - uint32_t write_area_width = fb.width - (WIDTH_MARGIN * 2) - (WRITE_AREA_MARGIN * 2); - uint32_t write_area_height = fb.height - (MARGIN_HEIGHT * 2) - HEADER_HEIGHT - (WRITE_AREA_MARGIN * 2); + write_area_x = WIDTH_MARGIN; + write_area_y = HEADER_HEIGHT + MARGIN_HEIGHT; + write_area_width = fb.width - (WIDTH_MARGIN * 2) - (WRITE_AREA_MARGIN * 2); + write_area_height = fb.height - (MARGIN_HEIGHT * 2) - HEADER_HEIGHT - (WRITE_AREA_MARGIN * 2); if(write_area_width % FONT_WIDTH){ write_area_x += (write_area_width % FONT_WIDTH) / 2; @@ -384,66 +585,19 @@ int main(int argc, char* argv[]){ write_area_height -= write_area_height % FONT_HEIGHT; } - cursor_x = write_area_x; - cursor_y = write_area_y; - char_row_count = write_area_width / FONT_WIDTH; char_col_count = write_area_height / FONT_HEIGHT; draw_rectangle(&fb, write_area_x - WRITE_AREA_MARGIN, write_area_y - WRITE_AREA_MARGIN, write_area_width + (2 * WRITE_AREA_MARGIN), write_area_height + (2 * WRITE_AREA_MARGIN), background_color); - while(!wait_escape()){ - draw_rectangle(&fb, 0, 0, fb.width, HEADER_HEIGHT, HEADER_BACKGROUND); - draw_rectangle(&fb, write_area_x, write_area_y, write_area_width, write_area_height, background_color); - - char* c = &text_buffer[text_index_start]; - uint16_t cx_pos = write_area_x; - uint16_t cy_pos = write_area_y; - - uint32_t col_count = 0; - uint32_t row_count = 0; - uint32_t c_count = 0; - while(*c && col_count < char_col_count){ - if(*c == '\n'){ - row_count = 0; - cx_pos = write_area_x; - cy_pos += FONT_HEIGHT; - col_count++; - }else if(*c == '\t'){ - row_count++; - cx_pos += FONT_WIDTH; - - row_count -= row_count % TAB_CHAR_COUNT; - row_count += TAB_CHAR_COUNT; - cx_pos -= (cx_pos - write_area_x) % (TAB_CHAR_COUNT * FONT_WIDTH); - cx_pos += TAB_CHAR_COUNT * FONT_WIDTH; - }else{ - if(row_count >= char_row_count){ - row_count = 0; - cx_pos = write_area_x; - cy_pos += FONT_HEIGHT; - col_count++; - if(col_count >= char_col_count){ - break; - } - } - - if(text_index_cursor == c_count && (get_ticks_ms() % (CURSOR_SHOW_DURATION_MS * 2)) < CURSOR_SHOW_DURATION_MS){ - draw_rectangle(&fb, cx_pos, cy_pos, FONT_WIDTH, FONT_HEIGHT, TEXT_COLOR); - bitmap_setchar(cx_pos, cy_pos, *c, ~TEXT_COLOR); - }else{ - bitmap_setchar(cx_pos, cy_pos, *c, TEXT_COLOR); - } - cx_pos += FONT_WIDTH; - row_count++; - } - - c_count++; - c++; - } + text_framebuffer = load_buffer(); + + while(!get_input()){ + draw_rectangle(&fb, 0, 0, fb.width, HEADER_HEIGHT, HEADER_BACKGROUND); + blit_framebuffer(&fb, text_framebuffer, write_area_x, write_area_y, write_area_height, copy_offset); char* image_reader_info = NULL; - assert(asprintf(&image_reader_info, "%s | %d/%d", argv[1], text_current_line + 1, text_lines_count) >= 0); + assert(asprintf(&image_reader_info, "%s", argv[1]) >= 0); write_paragraph(font, 0, 0, fb.width, PARAGRAPH_CENTER, image_reader_info); draw_frame(); diff --git a/sources/core/libs/kot-graphics/source/utils.h b/sources/core/libs/kot-graphics/source/utils.h index 4ab6d4295..1c203cd18 100644 --- a/sources/core/libs/kot-graphics/source/utils.h +++ b/sources/core/libs/kot-graphics/source/utils.h @@ -2,6 +2,7 @@ #define KOT_GRAPHICS_UTILS #include +#include #include #include #include @@ -24,5 +25,6 @@ uint32_t blend_colors(uint32_t color1, uint32_t color2, uint8_t factor); uint32_t blend_alpha(uint32_t color, uint8_t factor); void draw_rectangle(kframebuffer_t* fb, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color); void draw_rectangle_border(kframebuffer_t* fb, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color); +void blit_framebuffer(kframebuffer_t* to, kframebuffer_t* from, uint64_t position_x, uint64_t position_y, uint32_t max_height, size_t copy_offset); #endif // KOT_GRAPHICS_UTILS \ No newline at end of file diff --git a/sources/core/libs/kot-graphics/source/utils/utils.c b/sources/core/libs/kot-graphics/source/utils/utils.c index 623eb9b11..d0477617e 100644 --- a/sources/core/libs/kot-graphics/source/utils/utils.c +++ b/sources/core/libs/kot-graphics/source/utils/utils.c @@ -79,3 +79,30 @@ void draw_rectangle_border(kframebuffer_t* fb, uint32_t x, uint32_t y, uint32_t *(uint32_t*)((uint64_t)fb->buffer + (x + width - 1) * fb->btpp + (y + j) * fb->pitch) = color; } } + +void blit_framebuffer(kframebuffer_t* to, kframebuffer_t* from, uint64_t position_x, uint64_t position_y, uint32_t max_height, size_t copy_offset){ + uintptr_t to_buffer = (uintptr_t)to->buffer; + uintptr_t from_buffer = (uintptr_t)from->buffer + copy_offset; + + to_buffer += position_x * to->btpp + position_y * to->pitch; // offset + + uint64_t width_copy = from->width; + + if(position_x + width_copy >= to->width){ + width_copy = to->width - position_x; + } + + uint64_t height_copy = from->height; + + if(position_y + height_copy >= to->height){ + height_copy = to->height - position_y; + } + + uint64_t pitch_copy = width_copy * to->btpp; + + for(uint64_t h = 0; h < height_copy && h < max_height; h++){ + memcpy((void*)to_buffer, (void*)from_buffer, pitch_copy); + to_buffer += to->pitch; + from_buffer += from->pitch; + } +}