Repository: idea4good/GuiLite Branch: master Commit: 9b0790260406 Files: 42 Total size: 322.6 KB Directory structure: gitextract_g5h0to32/ ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ └── ccpp.yml ├── GuiLite.h ├── LICENSE ├── README.md ├── README_zh.md ├── documents/ │ ├── HowLayoutWork.md │ ├── HowMessageWork.md │ ├── HowToUse.md │ ├── HowToWork-cn.md │ ├── HowToWork.md │ └── UML.md └── src/ ├── .gitignore ├── CMakeLists.txt ├── GenerateGuiLite.h.sh ├── GuiLite.sln ├── GuiLite.uvprojx ├── GuiLite.vcxproj ├── GuiLite.vcxproj.filters ├── core/ │ ├── adapter/ │ │ ├── api_linux.cpp │ │ ├── api_unknow.cpp │ │ └── api_win.cpp │ ├── api.h │ ├── core.cpp │ ├── display.h │ ├── image.h │ ├── resource.h │ ├── theme.h │ ├── wnd.h │ └── word.h └── widgets/ ├── button.h ├── dialog.h ├── edit.h ├── keyboard.h ├── label.h ├── list_box.h ├── slide_group.h ├── spinbox.h ├── table.h ├── wave_buffer.h ├── wave_ctrl.h └── widgets.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ custom: https://idea4good.github.io/ ================================================ FILE: .github/workflows/ccpp.yml ================================================ name: C/C++ CI on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: cmake run: cd src && cmake . - name: make run: cd src && make ================================================ FILE: GuiLite.h ================================================ #pragma once #define REAL_TIME_TASK_CYCLE_MS 50 #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) #define GL_ARGB(a, r, g, b) ((((unsigned int)(a)) << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) #define GL_ARGB_A(rgb) ((((unsigned int)(rgb)) >> 24) & 0xFF) #define GL_RGB(r, g, b) ((0xFF << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) #define GL_RGB_R(rgb) ((((unsigned int)(rgb)) >> 16) & 0xFF) #define GL_RGB_G(rgb) ((((unsigned int)(rgb)) >> 8) & 0xFF) #define GL_RGB_B(rgb) (((unsigned int)(rgb)) & 0xFF) #define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8)) #define GL_RGB_16_to_32(rgb) ((0xFF << 24) | ((((unsigned int)(rgb)) & 0x1F) << 3) | ((((unsigned int)(rgb)) & 0x7E0) << 5) | ((((unsigned int)(rgb)) & 0xF800) << 8)) #define ALIGN_HCENTER 0x00000000L #define ALIGN_LEFT 0x01000000L #define ALIGN_RIGHT 0x02000000L #define ALIGN_HMASK 0x03000000L #define ALIGN_VCENTER 0x00000000L #define ALIGN_TOP 0x00100000L #define ALIGN_BOTTOM 0x00200000L #define ALIGN_VMASK 0x00300000L typedef struct { unsigned short year; unsigned short month; unsigned short date; unsigned short day; unsigned short hour; unsigned short minute; unsigned short second; }T_TIME; void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)); void _assert(const char* file, int line); #define ASSERT(condition) \ do{ \ if(!(condition))_assert(__FILE__, __LINE__);\ }while(0) void log_out(const char* log); long get_time_in_second(); T_TIME second_to_day(long second); T_TIME get_time(); void start_real_timer(void (*func)(void* arg)); void register_timer(int milli_second, void func(void* param), void* param); unsigned int get_cur_thread_id(); void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg); void thread_sleep(unsigned int milli_seconds); int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data); #define FIFO_BUFFER_LEN 1024 class c_fifo { public: c_fifo(); int read(void* buf, int len); int write(void* buf, int len); private: unsigned char m_buf[FIFO_BUFFER_LEN]; int m_head; int m_tail; void* m_read_sem; void* m_write_mutex; }; class c_rect { public: c_rect(){ m_left = m_top = m_right = m_bottom = -1; }//empty rect c_rect(int left, int top, int width, int height) { set_rect(left, top, width, height); } void set_rect(int left, int top, int width, int height) { ASSERT(width > 0 && height > 0); m_left = left; m_top = top; m_right = left + width - 1; m_bottom = top + height -1; } bool pt_in_rect(int x, int y) const { return x >= m_left && x <= m_right && y >= m_top && y <= m_bottom; } int operator==(const c_rect& rect) const { return (m_left == rect.m_left) && (m_top == rect.m_top) && (m_right == rect.m_right) && (m_bottom == rect.m_bottom); } int width() const { return m_right - m_left + 1; } int height() const { return m_bottom - m_top + 1 ; } int m_left; int m_top; int m_right; int m_bottom; }; //BITMAP typedef struct struct_bitmap_info { unsigned short width; unsigned short height; unsigned short color_bits;//support 16 bits only const unsigned short* pixel_color_array; } BITMAP_INFO; //FONT typedef struct struct_lattice { unsigned int utf8_code; unsigned char width; const unsigned char* pixel_buffer; } LATTICE; typedef struct struct_lattice_font_info { unsigned char height; unsigned int count; LATTICE* lattice_array; } LATTICE_FONT_INFO; //Rebuild gui library once you change this file enum FONT_LIST { FONT_NULL, FONT_DEFAULT, FONT_CUSTOM1, FONT_CUSTOM2, FONT_CUSTOM3, FONT_CUSTOM4, FONT_CUSTOM5, FONT_CUSTOM6, FONT_MAX }; enum IMAGE_LIST { IMAGE_CUSTOM1, IMAGE_CUSTOM2, IMAGE_CUSTOM3, IMAGE_CUSTOM4, IMAGE_CUSTOM5, IMAGE_CUSTOM6, IMAGE_MAX }; enum COLOR_LIST { COLOR_WND_FONT, COLOR_WND_NORMAL, COLOR_WND_PUSHED, COLOR_WND_FOCUS, COLOR_WND_BORDER, COLOR_CUSTOME1, COLOR_CUSTOME2, COLOR_CUSTOME3, COLOR_CUSTOME4, COLOR_CUSTOME5, COLOR_CUSTOME6, COLOR_MAX }; class c_theme { public: static int add_font(FONT_LIST index, const void* font) { if (index >= FONT_MAX) { ASSERT(false); return -1; } s_font_map[index] = font; return 0; } static const void* get_font(FONT_LIST index) { if (index >= FONT_MAX) { ASSERT(false); return 0; } return s_font_map[index]; } static int add_image(IMAGE_LIST index, const void* image_info) { if (index >= IMAGE_MAX) { ASSERT(false); return -1; } s_image_map[index] = image_info; return 0; } static const void* get_image(IMAGE_LIST index) { if (index >= IMAGE_MAX) { ASSERT(false); return 0; } return s_image_map[index]; } static int add_color(COLOR_LIST index, const unsigned int color) { if (index >= COLOR_MAX) { ASSERT(false); return -1; } s_color_map[index] = color; return 0; } static const unsigned int get_color(COLOR_LIST index) { if (index >= COLOR_MAX) { ASSERT(false); return 0; } return s_color_map[index]; } private: static const void* s_font_map[FONT_MAX]; static const void* s_image_map[IMAGE_MAX]; static unsigned int s_color_map[COLOR_MAX]; }; #include #include #include #define SURFACE_CNT_MAX 6//root + pages typedef enum { Z_ORDER_LEVEL_0,//lowest graphic level Z_ORDER_LEVEL_1,//middle graphic level, call activate_layer before use it, draw everything inside the active rect. Z_ORDER_LEVEL_2,//highest graphic level, call activate_layer before use it, draw everything inside the active rect. Z_ORDER_LEVEL_MAX }Z_ORDER_LEVEL; struct DISPLAY_DRIVER { void(*draw_pixel)(int x, int y, unsigned int rgb); void(*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb); }; class c_surface; class c_display { friend class c_surface; public: inline c_display(void* phy_fb, int display_width, int display_height, c_surface* surface, DISPLAY_DRIVER* driver = 0);//single custom surface inline c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, DISPLAY_DRIVER* driver = 0);//multiple surface inline c_surface* alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect = c_rect());//for slide group inline int swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset); int get_width() { return m_width; } int get_height() { return m_height; } void* get_phy_fb() { return m_phy_fb; } void* get_updated_fb(int* width, int* height, bool force_update = false) { if (width && height) { *width = m_width; *height = m_height; } if (force_update) { return m_phy_fb; } if (m_phy_read_index == m_phy_write_index) {//No update return 0; } m_phy_read_index = m_phy_write_index; return m_phy_fb; } int snap_shot(const char* file_name) { if (!m_phy_fb || (m_color_bytes !=2 && m_color_bytes != 4)) { return -1; } //16 bits framebuffer if (m_color_bytes == 2) { return build_bmp(file_name, m_width, m_height, (unsigned char*)m_phy_fb); } //32 bits framebuffer unsigned short* p_bmp565_data = new unsigned short[m_width * m_height]; unsigned int* p_raw_data = (unsigned int*)m_phy_fb; for (int i = 0; i < m_width * m_height; i++) { unsigned int rgb = *p_raw_data++; p_bmp565_data[i] = GL_RGB_32_to_16(rgb); } int ret = build_bmp(file_name, m_width, m_height, (unsigned char*)p_bmp565_data); delete[]p_bmp565_data; return ret; } protected: virtual void draw_pixel(int x, int y, unsigned int rgb) { if ((x >= m_width) || (y >= m_height)) { return; } if (m_driver && m_driver->draw_pixel) { return m_driver->draw_pixel(x, y, rgb); } if (m_color_bytes == 2) { ((unsigned short*)m_phy_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb); } else { ((unsigned int*)m_phy_fb)[y * m_width + x] = rgb; } } virtual void fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) { if (m_driver && m_driver->fill_rect) { return m_driver->fill_rect(x0, y0, x1, y1, rgb); } if (m_driver && m_driver->draw_pixel) { for (int y = y0; y <= y1; y++) { for (int x = x0; x <= x1; x++) { m_driver->draw_pixel(x, y, rgb); } } return; } int _width = m_width; int _height = m_height; int x, y; if (m_color_bytes == 2) { unsigned short* phy_fb; unsigned int rgb_16 = GL_RGB_32_to_16(rgb); for (y = y0; y <= y1; y++) { phy_fb = &((unsigned short*)m_phy_fb)[y * _width + x0]; for (x = x0; x <= x1; x++) { if ((x < _width) && (y < _height)) { *phy_fb++ = rgb_16; } } } } else { unsigned int* phy_fb; for (y = y0; y <= y1; y++) { phy_fb = &((unsigned int*)m_phy_fb)[y * _width + x0]; for (x = x0; x <= x1; x++) { if ((x < _width) && (y < _height)) { *phy_fb++ = rgb; } } } } } virtual int flush_screen(int left, int top, int right, int bottom, void* fb, int fb_width) { if ((0 == m_phy_fb) || (0 == fb)) { return -1; } int _width = m_width; int _height = m_height; left = (left >= _width) ? (_width - 1) : left; right = (right >= _width) ? (_width - 1) : right; top = (top >= _height) ? (_height - 1) : top; bottom = (bottom >= _height) ? (_height - 1) : bottom; for (int y = top; y < bottom; y++) { void* s_addr = (char*)fb + ((y * fb_width + left) * m_color_bytes); void* d_addr = (char*)m_phy_fb + ((y * _width + left) * m_color_bytes); memcpy(d_addr, s_addr, (right - left) * m_color_bytes); } return 0; } int m_width; //in pixels int m_height; //in pixels int m_color_bytes; //16/32 bits for default void* m_phy_fb; //physical framebuffer for default struct DISPLAY_DRIVER* m_driver; //Rendering by external method without default physical framebuffer int m_phy_read_index; int m_phy_write_index; c_surface* m_surface_group[SURFACE_CNT_MAX]; int m_surface_cnt; //surface count int m_surface_index; }; class c_layer { public: c_layer() { fb = 0; } void* fb; //framebuffer c_rect rect; //framebuffer area c_rect active_rect; }; class c_surface { friend class c_display; friend class c_bitmap_operator; public: Z_ORDER_LEVEL get_max_z_order() { return m_max_zorder; } c_surface(unsigned int width, unsigned int height, unsigned int color_bytes, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0, c_rect overlpa_rect = c_rect()) : m_width(width), m_height(height), m_color_bytes(color_bytes), m_fb(0), m_is_active(false), m_top_zorder(Z_ORDER_LEVEL_0), m_phy_write_index(0), m_display(0) { (overlpa_rect == c_rect()) ? set_surface(max_zorder, c_rect(0, 0, width, height)) : set_surface(max_zorder, overlpa_rect); } unsigned int get_pixel(int x, int y, unsigned int z_order) { if (x >= m_width || y >= m_height || x < 0 || y < 0 || z_order >= Z_ORDER_LEVEL_MAX) { ASSERT(false); return 0; } if (m_layers[z_order].fb) { return (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)(m_layers[z_order].fb))[y * m_width + x]) : ((unsigned int*)(m_layers[z_order].fb))[y * m_width + x]; } else if (m_fb) { return (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)m_fb)[y * m_width + x]) : ((unsigned int*)m_fb)[y * m_width + x]; } else if (m_display->m_phy_fb) { return (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)m_display->m_phy_fb)[y * m_width + x]) : ((unsigned int*)m_display->m_phy_fb)[y * m_width + x]; } return 0; } virtual void draw_pixel(int x, int y, unsigned int rgb, unsigned int z_order) { if (x >= m_width || y >= m_height || x < 0 || y < 0) { return; } if (z_order > (unsigned int)m_max_zorder) { ASSERT(false); return; } if (z_order > (unsigned int)m_top_zorder) { m_top_zorder = (Z_ORDER_LEVEL)z_order; } if (z_order == m_max_zorder) { return draw_pixel_low_level(x, y, rgb); } if (m_layers[z_order].rect.pt_in_rect(x, y)) { c_rect layer_rect = m_layers[z_order].rect; if (m_color_bytes == 2) { ((unsigned short*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = GL_RGB_32_to_16(rgb); } else { ((unsigned int*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = rgb; } } if (z_order == m_top_zorder) { return draw_pixel_low_level(x, y, rgb); } bool be_overlapped = false; for (unsigned int tmp_z_order = Z_ORDER_LEVEL_MAX - 1; tmp_z_order > z_order; tmp_z_order--) { if (m_layers[tmp_z_order].active_rect.pt_in_rect(x, y)) { be_overlapped = true; break; } } if (!be_overlapped) { draw_pixel_low_level(x, y, rgb); } } virtual void fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order) { x0 = (x0 < 0) ? 0 : x0; y0 = (y0 < 0) ? 0 : y0; x1 = (x1 > (m_width - 1)) ? (m_width - 1) : x1; y1 = (y1 > (m_height - 1)) ? (m_height - 1) : y1; if (z_order == m_max_zorder) { return fill_rect_low_level(x0, y0, x1, y1, rgb); } if (z_order == m_top_zorder) { int width = m_layers[z_order].rect.width(); c_rect layer_rect = m_layers[z_order].rect; unsigned int rgb_16 = GL_RGB_32_to_16(rgb); for (int y = y0; y <= y1; y++) { for (int x = x0; x <= x1; x++) { if (layer_rect.pt_in_rect(x, y)) { if (m_color_bytes == 2) { ((unsigned short*)m_layers[z_order].fb)[(y - layer_rect.m_top) * width + (x - layer_rect.m_left)] = rgb_16; } else { ((unsigned int*)m_layers[z_order].fb)[(y - layer_rect.m_top) * width + (x - layer_rect.m_left)] = rgb; } } } } return fill_rect_low_level(x0, y0, x1, y1, rgb); } for (; y0 <= y1; y0++) { draw_hline(x0, x1, y0, rgb, z_order); } } void draw_hline(int x0, int x1, int y, unsigned int rgb, unsigned int z_order) { for (; x0 <= x1; x0++) { draw_pixel(x0, y, rgb, z_order); } } void draw_vline(int x, int y0, int y1, unsigned int rgb, unsigned int z_order) { for (; y0 <= y1; y0++) { draw_pixel(x, y0, rgb, z_order); } } void draw_line(int x1, int y1, int x2, int y2, unsigned int rgb, unsigned int z_order) { int dx, dy, x, y, e; (x1 > x2) ? (dx = x1 - x2) : (dx = x2 - x1); (y1 > y2) ? (dy = y1 - y2) : (dy = y2 - y1); if (((dx > dy) && (x1 > x2)) || ((dx <= dy) && (y1 > y2))) { x = x2; y = y2; x2 = x1; y2 = y1; x1 = x; y1 = y; } x = x1; y = y1; if (dx > dy) { e = dy - dx / 2; for (; x1 <= x2; ++x1, e += dy) { draw_pixel(x1, y1, rgb, z_order); if (e > 0) { e -= dx; (y > y2) ? --y1 : ++y1; } } } else { e = dx - dy / 2; for (; y1 <= y2; ++y1, e += dx) { draw_pixel(x1, y1, rgb, z_order); if (e > 0) { e -= dy; (x > x2) ? --x1 : ++x1; } } } } void draw_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order, unsigned int size = 1) { for (unsigned int offset = 0; offset < size; offset++) { draw_hline(x0 + offset, x1 - offset, y0 + offset, rgb, z_order); draw_hline(x0 + offset, x1 - offset, y1 - offset, rgb, z_order); draw_vline(x0 + offset, y0 + offset, y1 - offset, rgb, z_order); draw_vline(x1 - offset, y0 + offset, y1 - offset, rgb, z_order); } } void draw_rect(c_rect rect, unsigned int rgb, unsigned int size, unsigned int z_order) { draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order, size); } void fill_rect(c_rect rect, unsigned int rgb, unsigned int z_order) { fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order); } int flush_screen(int left, int top, int right, int bottom) { if (!m_is_active) { return -1; } if (left < 0 || left >= m_width || right < 0 || right >= m_width || top < 0 || top >= m_height || bottom < 0 || bottom >= m_height) { ASSERT(false); } m_display->flush_screen(left, top, right, bottom, m_fb, m_width); *m_phy_write_index = *m_phy_write_index + 1; return 0; } bool is_active() { return m_is_active; } c_display* get_display() { return m_display; } void activate_layer(c_rect active_rect, unsigned int active_z_order)//empty active rect means inactivating the layer { ASSERT(active_z_order > Z_ORDER_LEVEL_0 && active_z_order <= Z_ORDER_LEVEL_MAX); //Show the layers below the current active rect. c_rect current_active_rect = m_layers[active_z_order].active_rect; for(int low_z_order = Z_ORDER_LEVEL_0; low_z_order < active_z_order; low_z_order++) { c_rect low_layer_rect = m_layers[low_z_order].rect; c_rect low_active_rect = m_layers[low_z_order].active_rect; void* fb = m_layers[low_z_order].fb; int width = low_layer_rect.width(); for (int y = current_active_rect.m_top; y <= current_active_rect.m_bottom; y++) { for (int x = current_active_rect.m_left; x <= current_active_rect.m_right; x++) { if (low_active_rect.pt_in_rect(x, y) && low_layer_rect.pt_in_rect(x, y))//active rect maybe is bigger than layer rect { unsigned int rgb = (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)fb)[(x - low_layer_rect.m_left) + (y - low_layer_rect.m_top) * width]) : ((unsigned int*)fb)[(x - low_layer_rect.m_left) + (y - low_layer_rect.m_top) * width]; draw_pixel_low_level(x, y, rgb); } } } } m_layers[active_z_order].active_rect = active_rect;//set the new acitve rect. } void set_active(bool flag) { m_is_active = flag; } protected: virtual void fill_rect_low_level(int x0, int y0, int x1, int y1, unsigned int rgb) {//fill rect on framebuffer of surface int x, y; if (m_color_bytes == 2) { unsigned short* fb; unsigned int rgb_16 = GL_RGB_32_to_16(rgb); for (y = y0; y <= y1; y++) { fb = m_fb ? &((unsigned short*)m_fb)[y * m_width + x0] : 0; if (!fb) { break; } for (x = x0; x <= x1; x++) { *fb++ = rgb_16; } } } else { unsigned int* fb; for (y = y0; y <= y1; y++) { fb = m_fb ? &((unsigned int*)m_fb)[y * m_width + x0] : 0; if (!fb) { break; } for (x = x0; x <= x1; x++) { *fb++ = rgb; } } } if (!m_is_active) { return; } m_display->fill_rect(x0, y0, x1, y1, rgb); *m_phy_write_index = *m_phy_write_index + 1; } virtual void draw_pixel_low_level(int x, int y, unsigned int rgb) { if (m_fb) {//draw pixel on framebuffer of surface (m_color_bytes == 2) ? ((unsigned short*)m_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb): ((unsigned int*)m_fb)[y * m_width + x] = rgb; } if (!m_is_active) { return; } m_display->draw_pixel(x, y, rgb); *m_phy_write_index = *m_phy_write_index + 1; } void attach_display(c_display* display) { ASSERT(display); m_display = display; m_phy_write_index = &display->m_phy_write_index; } void set_surface(Z_ORDER_LEVEL max_z_order, c_rect layer_rect) { m_max_zorder = max_z_order; if (m_display && (m_display->m_surface_cnt > 1)) { m_fb = calloc(m_width * m_height, m_color_bytes); } for (int i = Z_ORDER_LEVEL_0; i < m_max_zorder; i++) {//Top layber fb always be 0 ASSERT(m_layers[i].fb = calloc(layer_rect.width() * layer_rect.height(), m_color_bytes)); m_layers[i].rect = layer_rect; } m_layers[Z_ORDER_LEVEL_0].active_rect = layer_rect; } int m_width; //in pixels int m_height; //in pixels int m_color_bytes; //16 bits, 32 bits for default void* m_fb; //frame buffer you could see c_layer m_layers[Z_ORDER_LEVEL_MAX];//all graphic layers bool m_is_active; //active flag Z_ORDER_LEVEL m_max_zorder; //the highest graphic layer the surface will have Z_ORDER_LEVEL m_top_zorder; //the current highest graphic layer the surface have int* m_phy_write_index; c_display* m_display; }; inline c_display::c_display(void* phy_fb, int display_width, int display_height, c_surface* surface, DISPLAY_DRIVER* driver) : m_phy_fb(phy_fb), m_width(display_width), m_height(display_height), m_driver(driver), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(1), m_surface_index(0) { m_color_bytes = surface->m_color_bytes; surface->m_is_active = true; (m_surface_group[0] = surface)->attach_display(this); } inline c_display::c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, DISPLAY_DRIVER* driver) : m_phy_fb(phy_fb), m_width(display_width), m_height(display_height), m_color_bytes(color_bytes), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(surface_cnt), m_driver(driver), m_surface_index(0) { ASSERT(color_bytes == 2 || color_bytes == 4); ASSERT(m_surface_cnt <= SURFACE_CNT_MAX); memset(m_surface_group, 0, sizeof(m_surface_group)); for (int i = 0; i < m_surface_cnt; i++) { m_surface_group[i] = new c_surface(surface_width, surface_height, color_bytes); m_surface_group[i]->attach_display(this); } } inline c_surface* c_display::alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect) { ASSERT(max_zorder < Z_ORDER_LEVEL_MAX && m_surface_index < m_surface_cnt); (layer_rect == c_rect()) ? m_surface_group[m_surface_index]->set_surface(max_zorder, c_rect(0, 0, m_width, m_height)) : m_surface_group[m_surface_index]->set_surface(max_zorder, layer_rect); return m_surface_group[m_surface_index++]; } inline int c_display::swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset) { int surface_width = s0->m_width; int surface_height = s0->m_height; if (offset < 0 || offset > surface_width || y0 < 0 || y0 >= surface_height || y1 < 0 || y1 >= surface_height || x0 < 0 || x0 >= surface_width || x1 < 0 || x1 >= surface_width) { ASSERT(false); return -1; } int width = (x1 - x0 + 1); if (width < 0 || width > surface_width || width < offset) { ASSERT(false); return -1; } x0 = (x0 >= m_width) ? (m_width - 1) : x0; x1 = (x1 >= m_width) ? (m_width - 1) : x1; y0 = (y0 >= m_height) ? (m_height - 1) : y0; y1 = (y1 >= m_height) ? (m_height - 1) : y1; if (m_phy_fb) { for (int y = y0; y <= y1; y++) { //Left surface char* addr_s = ((char*)(s0->m_fb) + (y * surface_width + x0 + offset) * m_color_bytes); char* addr_d = ((char*)(m_phy_fb)+(y * m_width + x0) * m_color_bytes); memcpy(addr_d, addr_s, (width - offset) * m_color_bytes); //Right surface addr_s = ((char*)(s1->m_fb) + (y * surface_width + x0) * m_color_bytes); addr_d = ((char*)(m_phy_fb)+(y * m_width + x0 + (width - offset)) * m_color_bytes); memcpy(addr_d, addr_s, offset * m_color_bytes); } } else if (m_color_bytes == 2) { void(*draw_pixel)(int x, int y, unsigned int rgb) = m_driver->draw_pixel; for (int y = y0; y <= y1; y++) { //Left surface for (int x = x0; x <= (x1 - offset); x++) { draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s0->m_fb)[y * m_width + x + offset])); } //Right surface for (int x = x1 - offset; x <= x1; x++) { draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s1->m_fb)[y * m_width + x + offset - x1 + x0])); } } } else //m_color_bytes == 3/4... { void(*draw_pixel)(int x, int y, unsigned int rgb) = m_driver->draw_pixel; for (int y = y0; y <= y1; y++) { //Left surface for (int x = x0; x <= (x1 - offset); x++) { draw_pixel(x, y, ((unsigned int*)s0->m_fb)[y * m_width + x + offset]); } //Right surface for (int x = x1 - offset; x <= x1; x++) { draw_pixel(x, y, ((unsigned int*)s1->m_fb)[y * m_width + x + offset - x1 + x0]); } } } m_phy_write_index++; return 0; } #include #include #define VALUE_STR_LEN 16 class c_surface; class c_font_operator { public: virtual void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; virtual void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; virtual void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; virtual void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; virtual int get_str_size(const void* string, const void* font, int& width, int& height) = 0; void get_string_pos(const void* string, const void* font, c_rect rect, unsigned int align_type, int& x, int& y) { int x_size, y_size; get_str_size(string, font, x_size, y_size); int height = rect.m_bottom - rect.m_top + 1; int width = rect.m_right - rect.m_left + 1; x = y = 0; switch (align_type & ALIGN_HMASK) { case ALIGN_HCENTER: //m_text_org_x=0 if (width > x_size) { x = (width - x_size) / 2; } break; case ALIGN_LEFT: x = 0; break; case ALIGN_RIGHT: //m_text_org_x=0 if (width > x_size) { x = width - x_size; } break; default: ASSERT(0); break; } switch (align_type & ALIGN_VMASK) { case ALIGN_VCENTER: //m_text_org_y=0 if (height > y_size) { y = (height - y_size) / 2; } break; case ALIGN_TOP: y = 0; break; case ALIGN_BOTTOM: //m_text_org_y=0 if (height > y_size) { y = height - y_size; } break; default: ASSERT(0); break; } } }; class c_lattice_font_op : public c_font_operator { public: void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) { const char* s = (const char*)string; if (0 == s) { return; } int offset = 0; unsigned int utf8_code; while (*s) { s += get_utf8_code(s, utf8_code); offset += draw_single_char(surface, z_order, utf8_code, (x + offset), y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); } } void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) { const char* s = (const char*)string; if (0 == s) { return; } int x, y; get_string_pos(s, (const LATTICE_FONT_INFO*)font, rect, align_type, x, y); draw_string(surface, z_order, string, rect.m_left + x, rect.m_top + y, font, font_color, bg_color); } void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) { char buf[VALUE_STR_LEN]; value_2_string(value, dot_position, buf, VALUE_STR_LEN); draw_string(surface, z_order, buf, x, y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); } void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) { char buf[VALUE_STR_LEN]; value_2_string(value, dot_position, buf, VALUE_STR_LEN); draw_string_in_rect(surface, z_order, buf, rect, (const LATTICE_FONT_INFO*)font, font_color, bg_color, align_type); } int get_str_size(const void *string, const void* font, int& width, int& height) { const char* s = (const char*)string; if (0 == s || 0 == font) { width = height = 0; return -1; } int lattice_width = 0; unsigned int utf8_code; int utf8_bytes; while (*s) { utf8_bytes = get_utf8_code(s, utf8_code); const LATTICE* p_lattice = get_lattice((const LATTICE_FONT_INFO*)font, utf8_code); lattice_width += p_lattice ? p_lattice->width : ((const LATTICE_FONT_INFO*)font)->height; s += utf8_bytes; } width = lattice_width; height = ((const LATTICE_FONT_INFO*)font)->height; return 0; } private: void value_2_string(int value, int dot_position, char* buf, int len) { memset(buf, 0, len); switch (dot_position) { case 0: sprintf(buf, "%d", value); break; case 1: sprintf(buf, "%.1f", value * 1.0 / 10); break; case 2: sprintf(buf, "%.2f", value * 1.0 / 100); break; case 3: sprintf(buf, "%.3f", value * 1.0 / 1000); break; default: ASSERT(false); break; } } int draw_single_char(c_surface* surface, int z_order, unsigned int utf8_code, int x, int y, const LATTICE_FONT_INFO* font, unsigned int font_color, unsigned int bg_color) { unsigned int error_color = 0xFFFFFFFF; if (font) { const LATTICE* p_lattice = get_lattice(font, utf8_code); if (p_lattice) { draw_lattice(surface, z_order, x, y, p_lattice->width, font->height, p_lattice->pixel_buffer, font_color, bg_color); return p_lattice->width; } } else { error_color = GL_RGB(255, 0, 0); } //lattice/font not found, draw "X" int len = 16; for (int y_ = 0; y_ < len; y_++) { for (int x_ = 0; x_ < len; x_++) { int diff = (x_ - y_); int sum = (x_ + y_); (diff == 0 || diff == -1 || diff == 1 || sum == len || sum == (len - 1) || sum == (len + 1)) ? surface->draw_pixel((x + x_), (y + y_), error_color, z_order) : surface->draw_pixel((x + x_), (y + y_), 0, z_order); } } return len; } void draw_lattice(c_surface* surface, int z_order, int x, int y, int width, int height, const unsigned char* p_data, unsigned int font_color, unsigned int bg_color) { unsigned int r, g, b, rgb; unsigned char blk_value = *p_data++; unsigned char blk_cnt = *p_data++; b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; rgb = GL_RGB(r, g, b); for (int y_ = 0; y_ < height; y_++) { for (int x_ = 0; x_ < width; x_++) { ASSERT(blk_cnt); if (0x00 == blk_value) { if (GL_ARGB_A(bg_color)) { surface->draw_pixel(x + x_, y + y_, bg_color, z_order); } } else { surface->draw_pixel((x + x_), (y + y_), rgb, z_order); } if (--blk_cnt == 0) {//reload new block blk_value = *p_data++; blk_cnt = *p_data++; b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; rgb = GL_RGB(r, g, b); } } } } const LATTICE* get_lattice(const LATTICE_FONT_INFO* font, unsigned int utf8_code) { int first = 0; int last = font->count - 1; int middle = (first + last) / 2; while (first <= last) { if (font->lattice_array[middle].utf8_code < utf8_code) first = middle + 1; else if (font->lattice_array[middle].utf8_code == utf8_code) { return &font->lattice_array[middle]; } else { last = middle - 1; } middle = (first + last) / 2; } return 0; } static int get_utf8_code(const char* s, unsigned int& output_utf8_code) { static unsigned char s_utf8_length_table[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 }; unsigned char* us = (unsigned char*)s; int utf8_bytes = s_utf8_length_table[*us]; switch (utf8_bytes) { case 1: output_utf8_code = *us; break; case 2: output_utf8_code = (*us << 8) | (*(us + 1)); break; case 3: output_utf8_code = (*us << 16) | ((*(us + 1)) << 8) | *(us + 2); break; case 4: output_utf8_code = (*us << 24) | ((*(us + 1)) << 16) | (*(us + 2) << 8) | *(us + 3); break; default: ASSERT(false); break; } return utf8_bytes; } }; class c_word { public: static void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color)//string: char or wchar_t { fontOperator->draw_string(surface, z_order, string, x, y, font, font_color, bg_color); } static void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT)//string: char or wchar_t { fontOperator->draw_string_in_rect(surface, z_order, string, rect, font, font_color, bg_color, align_type); } static void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) { fontOperator->draw_value_in_rect(surface, z_order, value, dot_position, rect, font, font_color, bg_color, align_type); } static void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) { fontOperator->draw_value(surface, z_order, value, dot_position, x, y, font, font_color, bg_color); } static int get_str_size(const void* string, const void* font, int& width, int& height) { return fontOperator->get_str_size(string, font, width, height); } static c_font_operator* fontOperator; }; #define DEFAULT_MASK_COLOR 0xFF080408 class c_surface; class c_image_operator { public: virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; }; class c_bitmap_operator : public c_image_operator { public: virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { ASSERT(image_info); BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; unsigned short* lower_fb_16 = 0; unsigned int* lower_fb_32 = 0; int lower_fb_width = 0; c_rect lower_fb_rect; if (z_order >= Z_ORDER_LEVEL_1) { lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; lower_fb_rect = surface->m_layers[z_order - 1].rect; lower_fb_width = lower_fb_rect.width(); } unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); int xsize = pBitmap->width; int ysize = pBitmap->height; const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; int color_bytes = surface->m_color_bytes; for (int y_ = y; y_ < y + ysize; y_++) { for (int x_ = x; x_ < x + xsize; x_++) { unsigned int rgb = *pData++; if (mask_rgb_16 == rgb) { if (lower_fb_rect.pt_in_rect(x_, y_)) {//show lower layer surface->draw_pixel(x_, y_, (color_bytes == 4) ? lower_fb_32[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)] : GL_RGB_16_to_32(lower_fb_16[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)]), z_order); } } else { surface->draw_pixel(x_, y_, GL_RGB_16_to_32(rgb), z_order); } } } } virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { ASSERT(image_info); BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; if (0 == pBitmap || (src_x + width > pBitmap->width) || (src_y + height > pBitmap->height)) { return; } unsigned short* lower_fb_16 = 0; unsigned int* lower_fb_32 = 0; int lower_fb_width = 0; c_rect lower_fb_rect; if (z_order >= Z_ORDER_LEVEL_1) { lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; lower_fb_rect = surface->m_layers[z_order - 1].rect; lower_fb_width = lower_fb_rect.width(); } unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; int color_bytes = surface->m_color_bytes; for (int y_ = 0; y_ < height; y_++) { const unsigned short* p = &pData[src_x + (src_y + y_) * pBitmap->width]; for (int x_ = 0; x_ < width; x_++) { unsigned int rgb = *p++; if (mask_rgb_16 == rgb) { if (lower_fb_rect.pt_in_rect(x + x_, y + y_)) {//show lower layer surface->draw_pixel(x + x_, y + y_, (color_bytes == 4) ? lower_fb_32[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left] : GL_RGB_16_to_32(lower_fb_16[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left]), z_order); } } else { surface->draw_pixel(x + x_, y + y_, GL_RGB_16_to_32(rgb), z_order); } } } } }; class c_image { public: static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { image_operator->draw_image(surface, z_order, image_info, x, y, mask_rgb); } static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { image_operator->draw_image(surface, z_order, image_info, x, y, src_x, src_y, width, height, mask_rgb); } static c_image_operator* image_operator; }; class c_wnd; class c_surface; typedef enum { ATTR_VISIBLE = 0x40000000L, ATTR_FOCUS = 0x20000000L, ATTR_PRIORITY = 0x10000000L// Handle touch action at high priority }WND_ATTRIBUTION; typedef enum { STATUS_NORMAL, STATUS_PUSHED, STATUS_FOCUSED, STATUS_DISABLED }WND_STATUS; typedef enum { NAV_FORWARD, NAV_BACKWARD, NAV_ENTER }NAVIGATION_KEY; typedef enum { TOUCH_DOWN, TOUCH_UP }TOUCH_ACTION; typedef struct struct_wnd_tree { c_wnd* p_wnd;//window instance unsigned int resource_id;//ID const char* str;//caption short x;//position x short y;//position y short width; short height; struct struct_wnd_tree* p_child_tree;//sub tree }WND_TREE; typedef void (c_wnd::*WND_CALLBACK)(int, int); class c_wnd { public: c_wnd() : m_status(STATUS_NORMAL), m_attr((WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)), m_parent(0), m_top_child(0), m_prev_sibling(0), m_next_sibling(0), m_str(0), m_font_color(0), m_bg_color(0), m_id(0), m_z_order(Z_ORDER_LEVEL_0), m_focus_child(0), m_surface(0) {}; virtual ~c_wnd() {}; virtual int connect(c_wnd *parent, unsigned short resource_id, const char* str, short x, short y, short width, short height, WND_TREE* p_child_tree = 0) { if (0 == resource_id) { ASSERT(false); return -1; } m_id = resource_id; set_str(str); m_parent = parent; m_status = STATUS_NORMAL; if (parent) { m_z_order = parent->m_z_order; m_surface = parent->m_surface; } if (0 == m_surface) { ASSERT(false); return -2; } /* (cs.x = x * 1024 / 768) for 1027*768=>800*600 quickly*/ m_wnd_rect.m_left = x; m_wnd_rect.m_top = y; m_wnd_rect.m_right = (x + width - 1); m_wnd_rect.m_bottom = (y + height - 1); pre_create_wnd(); if (0 != parent) { parent->add_child_2_tail(this); } if (load_child_wnd(p_child_tree) >= 0) { on_init_children(); } return 0; } void disconnect() { if (0 != m_top_child) { c_wnd* child = m_top_child; c_wnd* next_child = 0; while (child) { next_child = child->m_next_sibling; child->disconnect(); child = next_child; } } if (0 != m_parent) { m_parent->unlink_child(this); } m_focus_child = 0; m_attr = WND_ATTRIBUTION(0); } virtual void on_init_children() {} virtual void on_paint() {} virtual void show_window() { if (ATTR_VISIBLE == (m_attr & ATTR_VISIBLE)) { on_paint(); c_wnd* child = m_top_child; if (0 != child) { while (child) { child->show_window(); child = child->m_next_sibling; } } } } unsigned short get_id() const { return m_id; } int get_z_order() { return m_z_order; } c_wnd* get_wnd_ptr(unsigned short id) const { c_wnd* child = m_top_child; while (child) { if (child->get_id() == id) { break; } child = child->m_next_sibling; } return child; } unsigned int get_attr() const { return m_attr; } void set_str(const char* str) { m_str = str; } void set_attr(WND_ATTRIBUTION attr) { m_attr = attr; } bool is_focus_wnd() const { return ((m_attr & ATTR_VISIBLE) && (m_attr & ATTR_FOCUS)) ? true : false; } void set_font_color(unsigned int color) { m_font_color = color; } unsigned int get_font_color() { return m_font_color; } void set_bg_color(unsigned int color) { m_bg_color = color; } unsigned int get_bg_color() { return m_bg_color; } void set_font_type(const LATTICE_FONT_INFO *font_type) { m_font = font_type; } const void* get_font_type() { return m_font; } void get_wnd_rect(c_rect &rect) const { rect = m_wnd_rect; } void get_screen_rect(c_rect &rect) const { int l = 0; int t = 0; wnd2screen(l, t); rect.set_rect(l, t, m_wnd_rect.width(), m_wnd_rect.height()); } c_wnd* set_child_focus(c_wnd *focus_child) { ASSERT(0 != focus_child); ASSERT(focus_child->m_parent == this); c_wnd* old_focus_child = m_focus_child; if (focus_child->is_focus_wnd()) { if (focus_child != old_focus_child) { if (old_focus_child) { old_focus_child->on_kill_focus(); } m_focus_child = focus_child; m_focus_child->on_focus(); } } return m_focus_child; } c_wnd* get_parent() const { return m_parent; } c_wnd* get_last_child() const { if (0 == m_top_child) { return 0; } c_wnd* child = m_top_child; while (child->m_next_sibling) { child = child->m_next_sibling; } return child; } int unlink_child(c_wnd *child) { if ((0 == child) || (this != child->m_parent)) { return -1; } if (0 == m_top_child) { return -2; } bool find = false; c_wnd* tmp_child = m_top_child; if (tmp_child == child) { m_top_child = child->m_next_sibling; if (0 != child->m_next_sibling) { child->m_next_sibling->m_prev_sibling = 0; } find = true; } else { while (tmp_child->m_next_sibling) { if (child == tmp_child->m_next_sibling) { tmp_child->m_next_sibling = child->m_next_sibling; if (0 != child->m_next_sibling) { child->m_next_sibling->m_prev_sibling = tmp_child; } find = true; break; } tmp_child = tmp_child->m_next_sibling; } } if (true == find) { if (m_focus_child == child) { m_focus_child = 0; } child->m_next_sibling = 0; child->m_prev_sibling = 0; return 1; } else { return 0; } } c_wnd* get_prev_sibling() const { return m_prev_sibling; } c_wnd* get_next_sibling() const { return m_next_sibling; } c_wnd* search_priority_sibling(c_wnd* root) { c_wnd* priority_wnd = 0; while (root) { if ((root->m_attr & ATTR_PRIORITY) && (root->m_attr & ATTR_VISIBLE)) { priority_wnd = root; break; } root = root->m_next_sibling; } return priority_wnd; } virtual void on_touch(int x, int y, TOUCH_ACTION action) { x -= m_wnd_rect.m_left; y -= m_wnd_rect.m_top; c_wnd* priority_wnd = search_priority_sibling(m_top_child); if (priority_wnd) { return priority_wnd->on_touch(x, y, action); } c_wnd* child = m_top_child; while (child) { if (child->is_focus_wnd()) { c_rect rect; child->get_wnd_rect(rect); if (true == rect.pt_in_rect(x, y)) { return child->on_touch(x, y, action); } } child = child->m_next_sibling; } } virtual void on_navigate(NAVIGATION_KEY key) { c_wnd* priority_wnd = search_priority_sibling(m_top_child); if (priority_wnd) { return priority_wnd->on_navigate(key); } if (!is_focus_wnd()) { return; } if (key != NAV_BACKWARD && key != NAV_FORWARD) { if (m_focus_child) { m_focus_child->on_navigate(key); } return; } // Move focus c_wnd* old_focus_wnd = m_focus_child; // No current focus wnd, new one. if (!old_focus_wnd) { c_wnd* child = m_top_child; c_wnd* new_focus_wnd = 0; while (child) { if (child->is_focus_wnd()) { new_focus_wnd = child; new_focus_wnd->m_parent->set_child_focus(new_focus_wnd); child = child->m_top_child; continue; } child = child->m_next_sibling; } return; } // Move focus from old wnd to next wnd c_wnd* next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_next_sibling : old_focus_wnd->m_prev_sibling; while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) {// Search neighbor of old focus wnd next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; } if (!next_focus_wnd) {// Search whole brother wnd next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_parent->m_top_child : old_focus_wnd->m_parent->get_last_child(); while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) { next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; } } if (next_focus_wnd) { next_focus_wnd->m_parent->set_child_focus(next_focus_wnd); } } c_surface* get_surface() { return m_surface; } void set_surface(c_surface* surface) { m_surface = surface; } protected: virtual void pre_create_wnd() {}; void add_child_2_tail(c_wnd *child) { if (0 == child)return; if (child == get_wnd_ptr(child->m_id))return; if (0 == m_top_child) { m_top_child = child; child->m_prev_sibling = 0; child->m_next_sibling = 0; } else { c_wnd* last_child = get_last_child(); if (0 == last_child) { ASSERT(false); } last_child->m_next_sibling = child; child->m_prev_sibling = last_child; child->m_next_sibling = 0; } } void wnd2screen(int &x, int &y) const { c_wnd* parent = m_parent; c_rect rect; x += m_wnd_rect.m_left; y += m_wnd_rect.m_top; while (0 != parent) { parent->get_wnd_rect(rect); x += rect.m_left; y += rect.m_top; parent = parent->m_parent; } } int load_child_wnd(WND_TREE *p_child_tree) { if (0 == p_child_tree) { return 0; } int sum = 0; WND_TREE* p_cur = p_child_tree; while (p_cur->p_wnd) { p_cur->p_wnd->connect(this, p_cur->resource_id, p_cur->str,p_cur->x, p_cur->y, p_cur->width, p_cur->height, p_cur->p_child_tree); p_cur++; sum++; } return sum; } void set_active_child(c_wnd* child) { m_focus_child = child; } virtual void on_focus() {}; virtual void on_kill_focus() {}; protected: unsigned short m_id; WND_STATUS m_status; WND_ATTRIBUTION m_attr; c_rect m_wnd_rect; //position relative to parent window. c_wnd* m_parent; //parent window c_wnd* m_top_child; //the first sub window would be navigated c_wnd* m_prev_sibling; //previous brother c_wnd* m_next_sibling; //next brother c_wnd* m_focus_child; //current focused window const char* m_str; //caption const void* m_font; //font face unsigned int m_font_color; unsigned int m_bg_color; int m_z_order; //the graphic level for rendering c_surface* m_surface; }; class c_button : public c_wnd { public: void set_on_click(WND_CALLBACK on_click) { this->on_click = on_click; } protected: virtual void on_paint() { c_rect rect; get_screen_rect(rect); switch (m_status) { case STATUS_NORMAL: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); if (m_str) { c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); } break; case STATUS_FOCUSED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); if (m_str) { c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); } break; case STATUS_PUSHED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); if (m_str) { c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); } break; default: ASSERT(false); break; } } virtual void on_focus() { m_status = STATUS_FOCUSED; on_paint(); } virtual void on_kill_focus() { m_status = STATUS_NORMAL; on_paint(); } virtual void pre_create_wnd() { on_click = 0; m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); } virtual void on_touch(int x, int y, TOUCH_ACTION action) { if (action == TOUCH_DOWN) { m_parent->set_child_focus(this); m_status = STATUS_PUSHED; on_paint(); } else { m_status = STATUS_FOCUSED; on_paint(); if(on_click) { (m_parent->*(on_click))(m_id, 0); } } } virtual void on_navigate(NAVIGATION_KEY key) { switch (key) { case NAV_ENTER: on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); break; case NAV_FORWARD: case NAV_BACKWARD: break; } return c_wnd::on_navigate(key); } WND_CALLBACK on_click; }; class c_surface; class c_dialog; typedef struct { c_dialog* dialog; c_surface* surface; } DIALOG_ARRAY; class c_dialog : public c_wnd { public: static int open_dialog(c_dialog* p_dlg, bool modal_mode = true) { if (0 == p_dlg) { ASSERT(false); return 0; } c_dialog* cur_dlg = get_the_dialog(p_dlg->get_surface()); if (cur_dlg == p_dlg) { return 1; } if (cur_dlg) { cur_dlg->set_attr(WND_ATTRIBUTION(0)); } c_rect rc; p_dlg->get_screen_rect(rc); p_dlg->get_surface()->activate_layer(rc, p_dlg->m_z_order); p_dlg->set_attr(modal_mode ? (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY) : (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)); p_dlg->show_window(); p_dlg->set_me_the_dialog(); return 1; } static int close_dialog(c_surface* surface) { c_dialog* dlg = get_the_dialog(surface); if (0 == dlg) { return 0; } dlg->set_attr(WND_ATTRIBUTION(0)); surface->activate_layer(c_rect(), dlg->m_z_order);//inactivate the layer of dialog by empty rect. //clear the dialog for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == surface) { ms_the_dialogs[i].dialog = 0; return 1; } } ASSERT(false); return -1; } static c_dialog* get_the_dialog(c_surface* surface) { for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == surface) { return ms_the_dialogs[i].dialog; } } return 0; } protected: virtual void pre_create_wnd() { m_attr = WND_ATTRIBUTION(0);// no focus/visible m_z_order = Z_ORDER_LEVEL_1; m_bg_color = GL_RGB(33, 42, 53); } virtual void on_paint() { c_rect rect; get_screen_rect(rect); m_surface->fill_rect(rect, m_bg_color, m_z_order); if (m_str) { c_word::draw_string(m_surface, m_z_order, m_str, rect.m_left + 35, rect.m_top, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0)); } } private: int set_me_the_dialog() { c_surface* surface = get_surface(); for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == surface) { ms_the_dialogs[i].dialog = this; return 0; } } for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == 0) { ms_the_dialogs[i].dialog = this; ms_the_dialogs[i].surface = surface; return 1; } } ASSERT(false); return -2; } static DIALOG_ARRAY ms_the_dialogs[SURFACE_CNT_MAX]; }; #include //Changing key width/height will change the width/height of keyboard #define KEY_WIDTH 65 #define KEY_HEIGHT 38 #define KEYBOARD_WIDTH ((KEY_WIDTH + 2) * 10) #define KEYBOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) #define NUM_BOARD_WIDTH ((KEY_WIDTH + 2) * 4) #define NUM_BOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) #define CAPS_WIDTH (KEY_WIDTH * 3 / 2) #define DEL_WIDTH (KEY_WIDTH * 3 / 2 + 1) #define ESC_WIDTH (KEY_WIDTH * 2 + 2) #define SWITCH_WIDTH (KEY_WIDTH * 3 / 2 ) #define SPACE_WIDTH (KEY_WIDTH * 3 + 2 * 2) #define DOT_WIDTH (KEY_WIDTH * 3 / 2 + 3) #define ENTER_WIDTH (KEY_WIDTH * 2 + 2) #define POS_X(c) ((KEY_WIDTH * c) + (c + 1) * 2) #define POS_Y(r) ((KEY_HEIGHT * r) + (r + 1) * 2) #define KEYBOARD_CLICK 0x5014 #define ON_KEYBORAD_UPDATE(func) \ {MSG_TYPE_WND, KEYBOARD_CLICK, 0, msgCallback(&func)}, typedef enum { STATUS_UPPERCASE, STATUS_LOWERCASE }KEYBOARD_STATUS; typedef enum { STYLE_ALL_BOARD, STYLE_NUM_BOARD }KEYBOARD_STYLE; typedef enum { CLICK_CHAR, CLICK_ENTER, CLICK_ESC }CLICK_STATUS; extern WND_TREE g_key_board_children[]; extern WND_TREE g_number_board_children[]; class c_keyboard: public c_wnd { public: c_keyboard() { m_attr = WND_ATTRIBUTION(0); } int open_keyboard(c_wnd *user, unsigned short resource_id, KEYBOARD_STYLE style, WND_CALLBACK on_click) { c_rect user_rect; user->get_wnd_rect(user_rect); if ((style != STYLE_ALL_BOARD) && (style != STYLE_NUM_BOARD)) { ASSERT(false); return -1; } if (style == STYLE_ALL_BOARD) {//Place keyboard at the bottom of user's parent window. c_rect user_parent_rect; user->get_parent()->get_wnd_rect(user_parent_rect); c_wnd::connect(user, resource_id, 0, (0 - user_rect.m_left), (user_parent_rect.height() - user_rect.m_top - KEYBOARD_HEIGHT - 1), KEYBOARD_WIDTH, KEYBOARD_HEIGHT, g_key_board_children); } else if (style == STYLE_NUM_BOARD) {//Place keyboard below the user window. c_wnd::connect(user, resource_id, 0, 0, user_rect.height(), NUM_BOARD_WIDTH, NUM_BOARD_HEIGHT, g_number_board_children); } m_on_click = on_click; c_rect rc; get_screen_rect(rc); m_surface->activate_layer(rc, m_z_order); show_window(); return 0; } void close_keyboard() { c_wnd::disconnect(); m_surface->activate_layer(c_rect(), m_z_order);//inactivate the layer of keyboard by empty rect. } virtual void on_init_children() { c_wnd* child = m_top_child; if (0 != child) { while (child) { ((c_button*)child)->set_on_click(WND_CALLBACK(&c_keyboard::on_key_clicked)); child = child->get_next_sibling(); } } } KEYBOARD_STATUS get_cap_status(){return m_cap_status;} char* get_str() { return m_str; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); m_cap_status = STATUS_UPPERCASE; m_z_order = m_surface->get_max_z_order(); memset(m_str, 0, sizeof(m_str)); m_str_len = 0; } virtual void on_paint() { c_rect rect; get_screen_rect(rect); m_surface->fill_rect(rect, GL_RGB(0, 0, 0), m_z_order); } void on_key_clicked(int id, int param) { switch (id) { case 0x14: on_caps_clicked(id, param); break; case '\n': on_enter_clicked(id, param); break; case 0x1B: on_esc_clicked(id, param); break; case 0x7F: on_del_clicked(id, param); break; default: on_char_clicked(id, param); break; } } void on_char_clicked(int id, int param) {//id = char ascii code. if (m_str_len >= sizeof(m_str)) { return; } if ((id >= '0' && id <= '9') || id == ' ' || id == '.') { goto InputChar; } if (id >= 'A' && id <= 'Z') { if (STATUS_LOWERCASE == m_cap_status) { id += 0x20; } goto InputChar; } if (id == 0x90) return;//TBD ASSERT(false); InputChar: m_str[m_str_len++] = id; (m_parent->*(m_on_click))(m_id, CLICK_CHAR); } void on_del_clicked(int id, int param) { if (m_str_len <= 0) { return; } m_str[--m_str_len] = 0; (m_parent->*(m_on_click))(m_id, CLICK_CHAR); } void on_caps_clicked(int id, int param) { m_cap_status = (m_cap_status == STATUS_LOWERCASE) ? STATUS_UPPERCASE : STATUS_LOWERCASE; show_window(); } void on_enter_clicked(int id, int param) { memset(m_str, 0, sizeof(m_str)); (m_parent->*(m_on_click))(m_id, CLICK_ENTER); } void on_esc_clicked(int id, int param) { memset(m_str, 0, sizeof(m_str)); (m_parent->*(m_on_click))(m_id, CLICK_ESC); } private: char m_str[32]; int m_str_len; KEYBOARD_STATUS m_cap_status; WND_CALLBACK m_on_click; }; class c_keyboard_button : public c_button { protected: virtual void on_paint() { c_rect rect; get_screen_rect(rect); switch (m_status) { case STATUS_NORMAL: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); break; case STATUS_FOCUSED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); break; case STATUS_PUSHED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); break; default: ASSERT(false); break; } if (m_id == 0x14) { return c_word::draw_string_in_rect(m_surface, m_z_order, "Caps", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == 0x1B) { return c_word::draw_string_in_rect(m_surface, m_z_order, "Esc", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == ' ') { return c_word::draw_string_in_rect(m_surface, m_z_order, "Space", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == '\n') { return c_word::draw_string_in_rect(m_surface, m_z_order, "Enter", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == '.') { return c_word::draw_string_in_rect(m_surface, m_z_order, ".", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == 0x7F) { return c_word::draw_string_in_rect(m_surface, m_z_order, "Back", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == 0x90) { return c_word::draw_string_in_rect(m_surface, m_z_order, "?123", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } char letter[] = { 0, 0 }; if (m_id >= 'A' && m_id <= 'Z') { letter[0] = (((c_keyboard*)m_parent)->get_cap_status() == STATUS_UPPERCASE) ? m_id : (m_id + 0x20); } else if (m_id >= '0' && m_id <= '9') { letter[0] = (char)m_id; } c_word::draw_string_in_rect(m_surface, m_z_order, letter, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } }; #include #define MAX_EDIT_STRLEN 32 #define IDD_KEY_BOARD 0x1 class c_edit : public c_wnd { friend class c_keyboard; public: const char* get_text(){return m_str;} void set_text(const char* str) { if (str != 0 && strlen(str) < sizeof(m_str)) { strcpy(m_str, str); } } void set_keyboard_style(KEYBOARD_STYLE kb_sytle) { m_kb_style = kb_sytle; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); m_kb_style = STYLE_ALL_BOARD; m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); memset(m_str_input, 0, sizeof(m_str_input)); memset(m_str, 0, sizeof(m_str)); set_text(c_wnd::m_str); } virtual void on_paint() { c_rect rect, kb_rect; get_screen_rect(rect); s_keyboard.get_screen_rect(kb_rect); switch (m_status) { case STATUS_NORMAL: if ((s_keyboard.get_attr()&ATTR_VISIBLE) == ATTR_VISIBLE) { s_keyboard.close_keyboard(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_FOCUSED: if ((s_keyboard.get_attr()&ATTR_VISIBLE) == ATTR_VISIBLE) { s_keyboard.close_keyboard(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_PUSHED: if ((s_keyboard.get_attr()&ATTR_VISIBLE) != ATTR_VISIBLE) { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); s_keyboard.open_keyboard(this, IDD_KEY_BOARD, m_kb_style, WND_CALLBACK(&c_edit::on_key_board_click)); } m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_PUSHED), m_parent->get_z_order()); m_surface->draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_BORDER), m_parent->get_z_order(), 2); strlen(m_str_input) ? c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str_input, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER) : c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); break; default: ASSERT(false); } } virtual void on_focus() { m_status = STATUS_FOCUSED; on_paint(); } virtual void on_kill_focus() { m_status = STATUS_NORMAL; on_paint(); } virtual void on_navigate(NAVIGATION_KEY key) { switch (key) { case NAV_ENTER: (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : (on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN), on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP)); return; case NAV_BACKWARD: case NAV_FORWARD: return (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : c_wnd::on_navigate(key); } } virtual void on_touch(int x, int y, TOUCH_ACTION action) { (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); } void on_key_board_click(int id, int param) { switch (param) { case CLICK_CHAR: strcpy(m_str_input, s_keyboard.get_str()); on_paint(); break; case CLICK_ENTER: if (strlen(m_str_input)) { memcpy(m_str, m_str_input, sizeof(m_str_input)); } m_status = STATUS_FOCUSED; on_paint(); break; case CLICK_ESC: memset(m_str_input, 0, sizeof(m_str_input)); m_status = STATUS_FOCUSED; on_paint(); break; default: ASSERT(false); break; } } private: void on_touch_down(int x, int y) { c_rect kb_rect_relate_2_edit_parent; s_keyboard.get_wnd_rect(kb_rect_relate_2_edit_parent); kb_rect_relate_2_edit_parent.m_left += m_wnd_rect.m_left; kb_rect_relate_2_edit_parent.m_right += m_wnd_rect.m_left; kb_rect_relate_2_edit_parent.m_top += m_wnd_rect.m_top; kb_rect_relate_2_edit_parent.m_bottom += m_wnd_rect.m_top; if (m_wnd_rect.pt_in_rect(x, y)) {//click edit box if (STATUS_NORMAL == m_status) { m_parent->set_child_focus(this); } } else if (kb_rect_relate_2_edit_parent.pt_in_rect(x, y)) {//click key board c_wnd::on_touch(x, y, TOUCH_DOWN); } else { if (STATUS_PUSHED == m_status) { m_status = STATUS_FOCUSED; on_paint(); } } } void on_touch_up(int x, int y) { if (STATUS_FOCUSED == m_status) { m_status = STATUS_PUSHED; on_paint(); } else if (STATUS_PUSHED == m_status) { if (m_wnd_rect.pt_in_rect(x, y)) {//click edit box m_status = STATUS_FOCUSED; on_paint(); } else { c_wnd::on_touch(x, y, TOUCH_UP); } } } static c_keyboard s_keyboard; KEYBOARD_STYLE m_kb_style; char m_str_input[MAX_EDIT_STRLEN]; char m_str[MAX_EDIT_STRLEN]; }; class c_label : public c_wnd { public: virtual void on_paint() { c_rect rect; unsigned int bg_color = m_bg_color ? m_bg_color : m_parent->get_bg_color(); get_screen_rect(rect); if (m_str) { m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, bg_color, m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, bg_color, ALIGN_LEFT | ALIGN_VCENTER); } } protected: virtual void pre_create_wnd() { m_attr = ATTR_VISIBLE; m_font_color = c_theme::get_color(COLOR_WND_FONT); m_font = c_theme::get_font(FONT_DEFAULT); } }; #include #define MAX_ITEM_NUM 4 #define ITEM_HEIGHT 45 class c_list_box : public c_wnd { public: void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } short get_item_count() { return m_item_total; } int add_item(char* str) { if (m_item_total >= MAX_ITEM_NUM) { ASSERT(false); return -1; } m_item_array[m_item_total++] = str; update_list_size(); return 0; } void clear_item() { m_selected_item = m_item_total = 0; memset(m_item_array, 0, sizeof(m_item_array)); update_list_size(); } void select_item(short index) { if (index < 0 || index >= m_item_total) { ASSERT(false); } m_selected_item = index; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); memset(m_item_array, 0, sizeof(m_item_array)); m_item_total = 0; m_selected_item = 0; m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); } virtual void on_paint() { c_rect rect; get_screen_rect(rect); switch (m_status) { case STATUS_NORMAL: if (m_z_order > m_parent->get_z_order()) { m_surface->activate_layer(c_rect(), m_z_order);//inactivate the layer of list by empty rect. m_z_order = m_parent->get_z_order(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_FOCUSED: if (m_z_order > m_parent->get_z_order()) { m_surface->activate_layer(c_rect(), m_z_order);//inactivate the layer of list by empty rect. m_z_order = m_parent->get_z_order(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_PUSHED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, GL_RGB(2, 124, 165), GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER | ALIGN_VCENTER); //draw list if (m_item_total > 0) { if (m_z_order == m_parent->get_z_order()) { m_z_order++; m_surface->activate_layer(m_list_screen_rect, m_z_order); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); } show_list(); } break; default: ASSERT(false); } } virtual void on_focus() { m_status = STATUS_FOCUSED; on_paint(); } virtual void on_kill_focus() { m_status = STATUS_NORMAL; on_paint(); } virtual void on_navigate(NAVIGATION_KEY key) { switch (key) { case NAV_ENTER: if (STATUS_PUSHED == m_status) { if(on_change) { (m_parent->*(on_change))(m_id, m_selected_item); } } on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); return; case NAV_BACKWARD: if (m_status != STATUS_PUSHED) { return c_wnd::on_navigate(key); } m_selected_item = (m_selected_item > 0) ? (m_selected_item - 1) : m_selected_item; return show_list(); case NAV_FORWARD: if (m_status != STATUS_PUSHED) { return c_wnd::on_navigate(key); } m_selected_item = (m_selected_item < (m_item_total - 1)) ? (m_selected_item + 1) : m_selected_item; return show_list(); } } virtual void on_touch(int x, int y, TOUCH_ACTION action) { (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); } private: void update_list_size() { m_list_wnd_rect = m_wnd_rect; m_list_wnd_rect.m_top = m_wnd_rect.m_bottom + 1; m_list_wnd_rect.m_bottom = m_list_wnd_rect.m_top + m_item_total * ITEM_HEIGHT; get_screen_rect(m_list_screen_rect); m_list_screen_rect.m_top = m_list_screen_rect.m_bottom + 1; m_list_screen_rect.m_bottom = m_list_screen_rect.m_top + m_item_total * ITEM_HEIGHT; } void show_list() { //draw all items c_rect tmp_rect; for (int i = 0; i < m_item_total; i++) { tmp_rect.m_left = m_list_screen_rect.m_left; tmp_rect.m_right = m_list_screen_rect.m_right; tmp_rect.m_top = m_list_screen_rect.m_top + i * ITEM_HEIGHT; tmp_rect.m_bottom = tmp_rect.m_top + ITEM_HEIGHT; if (m_selected_item == i) { m_surface->fill_rect(tmp_rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); } else { m_surface->fill_rect(tmp_rect, GL_RGB(17, 17, 17), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, GL_RGB(17, 17, 17), ALIGN_HCENTER | ALIGN_VCENTER); } } } void on_touch_down(int x, int y) { if (m_wnd_rect.pt_in_rect(x, y)) {//click base if (STATUS_NORMAL == m_status) { m_parent->set_child_focus(this); } } else if (m_list_wnd_rect.pt_in_rect(x, y)) {//click extend list c_wnd::on_touch(x, y, TOUCH_DOWN); } else { if (STATUS_PUSHED == m_status) { m_status = STATUS_FOCUSED; on_paint(); if(on_change) { (m_parent->*(on_change))(m_id, m_selected_item); } } } } void on_touch_up(int x, int y) { if (STATUS_FOCUSED == m_status) { m_status = STATUS_PUSHED; on_paint(); } else if (STATUS_PUSHED == m_status) { if (m_wnd_rect.pt_in_rect(x, y)) {//click base m_status = STATUS_FOCUSED; on_paint(); } else if (m_list_wnd_rect.pt_in_rect(x, y)) {//click extend list m_status = STATUS_FOCUSED; select_item((y - m_list_wnd_rect.m_top) / ITEM_HEIGHT); on_paint(); if(on_change) { (m_parent->*(on_change))(m_id, m_selected_item); } } else { c_wnd::on_touch(x, y, TOUCH_UP); } } } short m_selected_item; short m_item_total; char* m_item_array[MAX_ITEM_NUM]; c_rect m_list_wnd_rect; //rect relative to parent wnd. c_rect m_list_screen_rect; //rect relative to physical screen(frame buffer) WND_CALLBACK on_change; }; #include #define MAX_PAGES 5 class c_gesture; class c_slide_group : public c_wnd { public: inline c_slide_group(); int set_active_slide(int index, bool is_redraw = true) { if (index >= MAX_PAGES || index < 0) { return -1; } if (0 == m_slides[index]) { return -2; } m_active_slide_index = index; for (int i = 0; i < MAX_PAGES; i++) { if (m_slides[i] == 0) { continue; } if (i == index) { m_slides[i]->get_surface()->set_active(true); add_child_2_tail(m_slides[i]); if (is_redraw) { c_rect rc; get_screen_rect(rc); m_slides[i]->get_surface()->flush_screen(rc.m_left, rc.m_top, rc.m_right, rc.m_bottom); } } else { m_slides[i]->get_surface()->set_active(false); } } return 0; } c_wnd* get_slide(int index){return m_slides[index];} c_wnd* get_active_slide(){return m_slides[m_active_slide_index];} int get_active_slide_index(){return m_active_slide_index;} int add_slide(c_wnd* slide, unsigned short resource_id, short x, short y, short width, short height, WND_TREE* p_child_tree = 0, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0) { if (0 == slide) { return -1; } c_surface* old_surface = get_surface(); c_surface* new_surface = old_surface->get_display()->alloc_surface(max_zorder); new_surface->set_active(false); set_surface(new_surface); slide->connect(this, resource_id, 0, x, y, width, height, p_child_tree); set_surface(old_surface); int i = 0; while (i < MAX_PAGES) { if (m_slides[i] == slide) {//slide has lived ASSERT(false); return -2; } i++; } //new slide i = 0; while (i < MAX_PAGES) { if (m_slides[i] == 0) { m_slides[i] = slide; slide->show_window(); return 0; } i++; } //no more slide can be add ASSERT(false); return -3; } void disabel_all_slide() { for (int i = 0; i < MAX_PAGES; i++) { if (m_slides[i]) { m_slides[i]->get_surface()->set_active(false); } } } inline virtual void on_touch(int x, int y, TOUCH_ACTION action); virtual void on_navigate(NAVIGATION_KEY key) { if (m_slides[m_active_slide_index]) { m_slides[m_active_slide_index]->on_navigate(key); } } protected: c_wnd* m_slides[MAX_PAGES]; int m_active_slide_index; c_gesture* m_gesture; }; //#define SWIPE_STEP 300//for arm #define SWIPE_STEP 10//for PC & ANDROID #define MOVE_THRESHOLD 10 typedef enum { TOUCH_MOVE, TOUCH_IDLE }TOUCH_STATE; class c_slide_group; class c_gesture { public: c_gesture(c_slide_group* group) { m_slide_group = group; m_state = TOUCH_IDLE; m_down_x = m_down_y = m_move_x = m_move_y = 0; } bool handle_swipe(int x, int y, TOUCH_ACTION action) { if (action == TOUCH_DOWN)//MOUSE_LBUTTONDOWN { if (m_state == TOUCH_IDLE) { m_state = TOUCH_MOVE; m_move_x = m_down_x = x; return true; } else//TOUCH_MOVE { return on_move(x); } } else if (action == TOUCH_UP)//MOUSE_LBUTTONUP { if (m_state == TOUCH_MOVE) { m_state = TOUCH_IDLE; return on_swipe(x); } else { return false; //ASSERT(false); } } return true; } private: bool on_move(int x) { if (m_slide_group == 0) { return true; } if (abs(x - m_move_x) < MOVE_THRESHOLD) { return false; } m_slide_group->disabel_all_slide(); m_move_x = x; if ((m_move_x - m_down_x) > 0) { move_right(); } else { move_left(); } return false; } bool on_swipe(int x) { if (m_slide_group == 0) { return true; } if ((m_down_x == m_move_x) && (abs(x - m_down_x) < MOVE_THRESHOLD)) { return true; } m_slide_group->disabel_all_slide(); int page = -1; m_move_x = x; if ((m_move_x - m_down_x) > 0) { page = swipe_right(); } else { page = swipe_left(); } if (page >= 0) { m_slide_group->set_active_slide(page); } else { m_slide_group->set_active_slide(m_slide_group->get_active_slide_index(), false); } return false; } int swipe_left() { if (m_slide_group == 0) { return -1; } int index = m_slide_group->get_active_slide_index(); if ((index + 1) >= MAX_PAGES || m_slide_group->get_slide(index + 1) == 0 || m_slide_group->get_slide(index) == 0) { return -2; } c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); if (s1->get_display() != s2->get_display()) { return -3; } int step = m_down_x - m_move_x; c_rect rc; m_slide_group->get_screen_rect(rc); while (step < rc.width()) { s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); step += SWIPE_STEP; } if (step != rc.width()) { s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, rc.width()); } return (index + 1); } int swipe_right() { if (m_slide_group == 0) { return -1; } int index = m_slide_group->get_active_slide_index(); if (index <= 0 || m_slide_group->get_slide(index - 1) == 0 || m_slide_group->get_slide(index) == 0) { return -2; } c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); if (s1->get_display() != s2->get_display()) { return -3; } c_rect rc; m_slide_group->get_screen_rect(rc); int step = rc.width() - (m_move_x - m_down_x); while (step > 0) { s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); step -= SWIPE_STEP; } if (step != 0) { s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, 0); } return (index - 1); } void move_left() { int index = m_slide_group->get_active_slide_index(); if ((index + 1) >= MAX_PAGES || m_slide_group->get_slide(index + 1) == 0 || m_slide_group->get_slide(index) == 0) { return; } c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); c_rect rc; m_slide_group->get_screen_rect(rc); if (s1->get_display() == s2->get_display()) { s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (m_down_x - m_move_x)); } } void move_right() { int index = m_slide_group->get_active_slide_index(); if (index <= 0 || m_slide_group->get_slide(index - 1) == 0 || m_slide_group->get_slide(index) == 0) { return; } c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); c_rect rc; m_slide_group->get_screen_rect(rc); if (s1->get_display() == s2->get_display()) { s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (rc.width() - (m_move_x - m_down_x))); } } int m_down_x; int m_down_y; int m_move_x; int m_move_y; TOUCH_STATE m_state; c_slide_group* m_slide_group; }; inline c_slide_group::c_slide_group() { m_gesture = new c_gesture(this); for (int i = 0; i < MAX_PAGES; i++) { m_slides[i] = 0; } m_active_slide_index = 0; } inline void c_slide_group::on_touch(int x, int y, TOUCH_ACTION action) { x -= m_wnd_rect.m_left; y -= m_wnd_rect.m_top; if (m_gesture->handle_swipe(x, y, action)) { if (m_slides[m_active_slide_index]) { m_slides[m_active_slide_index]->on_touch(x, y, action); } } } #define ID_BT_ARROW_UP 0x1111 #define ID_BT_ARROW_DOWN 0x2222 class c_spin_box; class c_spin_button : public c_button { friend class c_spin_box; inline virtual void on_touch(int x, int y, TOUCH_ACTION action); c_spin_box* m_spin_box; }; class c_spin_box : public c_wnd { friend class c_spin_button; public: short get_value() { return m_value; } void set_value(unsigned short value) { m_value = m_cur_value = value; } void set_max_min(short max, short min) { m_max = max; m_min = min; } void set_step(short step) { m_step = step; } short get_min() { return m_min; } short get_max() { return m_max; } short get_step() { return m_step; } void set_value_digit(short digit) { m_digit = digit; } short get_value_digit() { return m_digit; } void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } protected: virtual void on_paint() { c_rect rect; get_screen_rect(rect); rect.m_right = rect.m_left + (rect.width() * 2 / 3); m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); c_word::draw_value_in_rect(m_surface, m_parent->get_z_order(), m_cur_value, m_digit, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); } virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); m_max = 6; m_min = 1; m_digit = 0; m_step = 1; //link arrow button position. c_rect rect; get_wnd_rect(rect); m_bt_down.m_spin_box = m_bt_up.m_spin_box = this; m_bt_up.connect(m_parent, ID_BT_ARROW_UP, "+", (rect.m_left + rect.width() * 2 / 3), rect.m_top, (rect.width() / 3), (rect.height() / 2)); m_bt_down.connect(m_parent, ID_BT_ARROW_DOWN, "-", (rect.m_left + rect.width() * 2 / 3), (rect.m_top + rect.height() / 2), (rect.width() / 3), (rect.height() / 2)); } void on_arrow_up_bt_click() { if (m_cur_value + m_step > m_max) { return; } m_cur_value += m_step; if(on_change) { (m_parent->*(on_change))(m_id, m_cur_value); } on_paint(); } void on_arrow_down_bt_click() { if (m_cur_value - m_step < m_min) { return; } m_cur_value -= m_step; if(on_change) { (m_parent->*(on_change))(m_id, m_cur_value); } on_paint(); } short m_cur_value; short m_value; short m_step; short m_max; short m_min; short m_digit; c_spin_button m_bt_up; c_spin_button m_bt_down; WND_CALLBACK on_change; }; inline void c_spin_button::on_touch(int x, int y, TOUCH_ACTION action) { if (action == TOUCH_UP) { (m_id == ID_BT_ARROW_UP) ? m_spin_box->on_arrow_up_bt_click() : m_spin_box->on_arrow_down_bt_click(); } c_button::on_touch(x, y, action); } #define MAX_COL_NUM 30 #define MAX_ROW_NUM 30 class c_table: public c_wnd { public: void set_sheet_align(unsigned int align_type){ m_align_type = align_type;} void set_row_num(unsigned int row_num){ m_row_num = row_num;} void set_col_num(unsigned int col_num){ m_col_num = col_num;} void set_row_height(unsigned int height) { for (unsigned int i = 0; i < m_row_num; i++) { m_row_height[i] = height; } } void set_col_width(unsigned int width) { for (unsigned int i = 0; i < m_col_num; i++) { m_col_width[i] = width; } } int set_row_height(unsigned int index, unsigned int height) { if (m_row_num > index) { m_row_height[index] = height; return index; } return -1; } int set_col_width(unsigned int index, unsigned int width) { if (m_col_num > index) { m_col_width[index] = width; return index; } return -1; } void set_item(int row, int col, char* str, unsigned int color) { draw_item(row, col, str, color); } unsigned int get_row_num(){ return m_row_num;} unsigned int get_col_num(){ return m_col_num;} c_rect get_item_rect(int row, int col) { static c_rect rect; if (row >= MAX_ROW_NUM || col >= MAX_COL_NUM) { return rect; } unsigned int width = 0; unsigned int height = 0; for (int i = 0; i < col; i++) { width += m_col_width[i]; } for (int j = 0; j < row; j++) { height += m_row_height[j]; } c_rect wRect; get_screen_rect(wRect); rect.m_left = wRect.m_left + width; rect.m_right = rect.m_left + m_col_width[col]; if (rect.m_right > wRect.m_right) { rect.m_right = wRect.m_right; } rect.m_top = wRect.m_top + height; rect.m_bottom = rect.m_top + m_row_height[row]; if (rect.m_bottom > wRect.m_bottom) { rect.m_bottom = wRect.m_bottom; } return rect; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); } void draw_item(int row, int col, const char* str, unsigned int color) { c_rect rect = get_item_rect(row, col); m_surface->fill_rect(rect.m_left + 1, rect.m_top + 1, rect.m_right - 1, rect.m_bottom - 1, color, m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, str, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_align_type); } unsigned int m_align_type; unsigned int m_row_num; unsigned int m_col_num; unsigned int m_row_height[MAX_ROW_NUM]; unsigned int m_col_width[MAX_COL_NUM]; }; #include #include #define WAVE_BUFFER_LEN 1024 #define WAVE_READ_CACHE_LEN 8 #define BUFFER_EMPTY -1111 #define BUFFER_FULL -2222; class c_wave_buffer { public: c_wave_buffer() { m_head = m_tail = m_min_old = m_max_old = m_min_older = m_max_older = m_last_data = m_read_cache_sum = m_refresh_sequence = 0; memset(m_wave_buf, 0, sizeof(m_wave_buf)); memset(m_read_cache_min, 0, sizeof(m_read_cache_min)); memset(m_read_cache_mid, 0, sizeof(m_read_cache_mid)); memset(m_read_cache_max, 0, sizeof(m_read_cache_max)); } int write_wave_data(short data) { if ((m_tail + 1) % WAVE_BUFFER_LEN == m_head) {//full //log_out("wave buf full\n"); return BUFFER_FULL; } m_wave_buf[m_tail] = data; m_tail = (m_tail + 1) % WAVE_BUFFER_LEN; return 1; } int read_wave_data_by_frame(short &max, short &min, short frame_len, unsigned int sequence, short offset) { if (m_refresh_sequence != sequence) { m_refresh_sequence = sequence; m_read_cache_sum = 0; } else if (offset < m_read_cache_sum)//(m_refresh_sequence == sequence && offset < m_fb_sum) { max = m_read_cache_max[offset]; min = m_read_cache_min[offset]; return m_read_cache_mid[offset]; } m_read_cache_sum++; ASSERT(m_read_cache_sum <= WAVE_READ_CACHE_LEN); int i, data; int tmp_min = m_last_data; int tmp_max = m_last_data; int mid = (m_min_old + m_max_old) >> 1; i = 0; while (i++ < frame_len) { data = read_data(); if (BUFFER_EMPTY == data) { break; } m_last_data = data; if (data < tmp_min) { tmp_min = data; } if (data > tmp_max) { tmp_max = data; } } min = m_read_cache_min[offset] = MIN(m_min_old, MIN(tmp_min, m_min_older)); max = m_read_cache_max[offset] = MAX(m_max_old, MAX(tmp_max, m_max_older)); m_min_older = m_min_old; m_max_older = m_max_old; m_min_old = tmp_min; m_max_old = tmp_max; return (m_read_cache_mid[offset] = mid); } void reset() { m_head = m_tail; } void clear_data() { m_head = m_tail = 0; memset(m_wave_buf, 0, sizeof(m_wave_buf)); } short get_cnt() { return (m_tail >= m_head) ? (m_tail - m_head) : (m_tail - m_head + WAVE_BUFFER_LEN); } private: int read_data() { if (m_head == m_tail) {//empty //log_out("wave buf empty\n"); return BUFFER_EMPTY; } int ret = m_wave_buf[m_head]; m_head = (m_head + 1) % WAVE_BUFFER_LEN; return ret; } short m_wave_buf[WAVE_BUFFER_LEN]; short m_head; short m_tail; int m_min_old; int m_max_old; int m_min_older; int m_max_older; int m_last_data; short m_read_cache_min[WAVE_READ_CACHE_LEN]; short m_read_cache_mid[WAVE_READ_CACHE_LEN]; short m_read_cache_max[WAVE_READ_CACHE_LEN]; short m_read_cache_sum; unsigned int m_refresh_sequence; }; #include #include #define CORRECT(x, high_limit, low_limit) {\ x = (x > high_limit) ? high_limit : x;\ x = (x < low_limit) ? low_limit : x;\ }while(0) #define WAVE_CURSOR_WIDTH 8 #define WAVE_LINE_WIDTH 1 #define WAVE_MARGIN 5 typedef enum { FILL_MODE, SCAN_MODE }E_WAVE_DRAW_MODE; class c_wave_buffer; class c_wave_ctrl : public c_wnd { public: c_wave_ctrl() { m_wave = 0; m_bg_fb = 0; m_wave_name_font = m_wave_unit_font = 0; m_wave_name = m_wave_unit = 0; m_max_data = 500; m_min_data = 0; m_wave_speed = 1; m_wave_data_rate = 0; m_wave_refresh_rate = 1000; m_frame_len_map_index = 0; m_wave_name_color = m_wave_unit_color = m_wave_color = GL_RGB(255, 0, 0); m_back_color = GL_RGB(0, 0, 0); } virtual void on_init_children()//should be pre_create { c_rect rect; get_screen_rect(rect); m_wave_left = rect.m_left + WAVE_MARGIN; m_wave_right = rect.m_right - WAVE_MARGIN; m_wave_top = rect.m_top + WAVE_MARGIN; m_wave_bottom = rect.m_bottom - WAVE_MARGIN; m_wave_cursor = m_wave_left; m_bg_fb = (unsigned int*)calloc(rect.width() * rect.height(), 4); } virtual void on_paint() { c_rect rect; get_screen_rect(rect); m_surface->fill_rect(rect, m_back_color, m_z_order); //show name c_word::draw_string(m_surface, m_z_order, m_wave_name, m_wave_left + 10, rect.m_top, m_wave_name_font, m_wave_name_color, GL_ARGB(0, 0, 0, 0)); //show unit c_word::draw_string(m_surface, m_z_order, m_wave_unit, m_wave_left + 60, rect.m_top, m_wave_unit_font, m_wave_unit_color, GL_ARGB(0, 0, 0, 0)); save_background(); } void set_wave_name(char* wave_name){ m_wave_name = wave_name;} void set_wave_unit(char* wave_unit){ m_wave_unit = wave_unit;} void set_wave_name_font(const LATTICE_FONT_INFO* wave_name_font_type){ m_wave_name_font = wave_name_font_type;} void set_wave_unit_font(const LATTICE_FONT_INFO* wave_unit_font_type){ m_wave_unit_font = wave_unit_font_type;} void set_wave_name_color(unsigned int wave_name_color){ m_wave_name_color = wave_name_color;} void set_wave_unit_color(unsigned int wave_unit_color){ m_wave_unit_color = wave_unit_color;} void set_wave_color(unsigned int color){ m_wave_color = color;} void set_wave_in_out_rate(unsigned int data_rate, unsigned int refresh_rate) { m_wave_data_rate = data_rate; m_wave_refresh_rate = refresh_rate; int read_times_per_second = m_wave_speed * 1000 / m_wave_refresh_rate; memset(m_frame_len_map, 0, sizeof(m_frame_len_map)); for (unsigned int i = 1; i < sizeof(m_frame_len_map) + 1; i++) { m_frame_len_map[i - 1] = data_rate * i / read_times_per_second - data_rate * (i - 1) / read_times_per_second; } m_frame_len_map_index = 0; } void set_wave_speed(unsigned int speed) { m_wave_speed = speed; set_wave_in_out_rate(m_wave_data_rate, m_wave_refresh_rate); } void set_max_min(short max_data, short min_data) { m_max_data = max_data; m_min_data = min_data; } void set_wave(c_wave_buffer* wave){m_wave = wave;} c_wave_buffer* get_wave(){return m_wave;} void clear_data() { if (m_wave == 0) { ASSERT(false); return; } m_wave->clear_data(); } bool is_data_enough() { if (m_wave == 0) { ASSERT(false); return false; } return (m_wave->get_cnt() - m_frame_len_map[m_frame_len_map_index] * m_wave_speed); } void refresh_wave(unsigned char frame) { if (m_wave == 0) { ASSERT(false); return; } short max, min, mid; for (short offset = 0; offset < m_wave_speed; offset++) { //get wave value mid = m_wave->read_wave_data_by_frame(max, min, m_frame_len_map[m_frame_len_map_index++], frame, offset); m_frame_len_map_index %= sizeof(m_frame_len_map); //map to wave ctrl int y_min, y_max; if (m_max_data == m_min_data) { ASSERT(false); } y_max = m_wave_bottom + WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (min - m_min_data) / (m_max_data - m_min_data); y_min = m_wave_bottom - WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (max - m_min_data) / (m_max_data - m_min_data); mid = m_wave_bottom - (m_wave_bottom - m_wave_top) * (mid - m_min_data) / (m_max_data - m_min_data); CORRECT(y_min, m_wave_bottom, m_wave_top); CORRECT(y_max, m_wave_bottom, m_wave_top); CORRECT(mid, m_wave_bottom, m_wave_top); if (m_wave_cursor > m_wave_right) { m_wave_cursor = m_wave_left; } draw_smooth_vline(y_min, y_max, mid, m_wave_color); restore_background(); m_wave_cursor++; } } void clear_wave() { m_surface->fill_rect(m_wave_left, m_wave_top, m_wave_right, m_wave_bottom, m_back_color, m_z_order); m_wave_cursor = m_wave_left; } protected: void draw_smooth_vline(int y_min, int y_max, int mid, unsigned int rgb) { int dy = y_max - y_min; short r = GL_RGB_R(rgb); short g = GL_RGB_G(rgb); short b = GL_RGB_B(rgb); int index = (dy >> 1) + 2; int y; m_surface->draw_pixel(m_wave_cursor, mid, rgb, m_z_order); if (dy < 1) { return; } unsigned char cur_r, cur_g, cur_b; unsigned int cur_rgb; for (int i = 1; i <= (dy >> 1) + 1; ++i) { if ((mid + i) <= y_max) { y = mid + i; cur_r = r * (index - i) / index; cur_g = g * (index - i) / index; cur_b = b * (index - i) / index; cur_rgb = GL_RGB(cur_r, cur_g, cur_b); m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); } if ((mid - i) >= y_min) { y = mid - i; cur_r = r * (index - i) / index; cur_g = g * (index - i) / index; cur_b = b * (index - i) / index; cur_rgb = GL_RGB(cur_r, cur_g, cur_b); m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); } } } void restore_background() { int x = m_wave_cursor + WAVE_CURSOR_WIDTH; if (x > m_wave_right) { x -= (m_wave_right - m_wave_left + 1); } c_rect rect; get_screen_rect(rect); int width = rect.width(); int top = rect.m_top; int left = rect.m_left; for (int y_pos = (m_wave_top - 1); y_pos <= (m_wave_bottom + 1); y_pos++) { (m_bg_fb) ? m_surface->draw_pixel(x, y_pos, m_bg_fb[(y_pos - top) * width + (x - left)], m_z_order) : m_surface->draw_pixel(x, y_pos, 0, m_z_order); } } void save_background() { if (!m_bg_fb) { return; } c_rect rect; get_screen_rect(rect); unsigned int* p_des = m_bg_fb; for (int y = rect.m_top; y <= rect.m_bottom; y++) { for (int x = rect.m_left; x <= rect.m_right; x++) { *p_des++ = m_surface->get_pixel(x, y, m_z_order); } } } char* m_wave_name; char* m_wave_unit; const LATTICE_FONT_INFO* m_wave_name_font; const LATTICE_FONT_INFO* m_wave_unit_font; unsigned int m_wave_name_color; unsigned int m_wave_unit_color; unsigned int m_wave_color; unsigned int m_back_color; int m_wave_left; int m_wave_right; int m_wave_top; int m_wave_bottom; short m_max_data; short m_min_data; private: c_wave_buffer* m_wave; unsigned int* m_bg_fb; //background frame buffer, could be used to draw scale line. int m_wave_cursor; int m_wave_speed; //pixels per refresh unsigned int m_wave_data_rate; //data sample rate unsigned int m_wave_refresh_rate;//refresh cycle in millisecond unsigned char m_frame_len_map[64]; unsigned char m_frame_len_map_index; }; #ifdef GUILITE_ON c_bitmap_operator the_bitmap_op = c_bitmap_operator(); c_image_operator* c_image::image_operator = &the_bitmap_op; const void* c_theme::s_font_map[FONT_MAX]; const void* c_theme::s_image_map[IMAGE_MAX]; unsigned int c_theme::s_color_map[COLOR_MAX]; c_lattice_font_op the_lattice_font_op = c_lattice_font_op(); c_font_operator* c_word::fontOperator = &the_lattice_font_op; #endif #ifdef GUILITE_ON #if ((defined __linux__) && (!defined __none_os__)) || (defined __APPLE__) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_TIMER_CNT 10 #define TIMER_UNIT 50//ms static void(*do_assert)(const char* file, int line); static void(*do_log_out)(const char* log); void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) { do_assert = my_assert; do_log_out = my_log_out; } void _assert(const char* file, int line) { if(do_assert) { do_assert(file, line); } else { printf("assert@ file:%s, line:%d, error no: %d\n", file, line, errno); } } void log_out(const char* log) { if (do_log_out) { do_log_out(log); } else { printf("%s", log); fflush(stdout); } } typedef struct _timer_manage { struct _timer_info { int state; /* on or off */ int interval; int elapse; /* 0~interval */ void (* timer_proc) (void* param); void* param; }timer_info[MAX_TIMER_CNT]; void (* old_sigfunc)(int); void (* new_sigfunc)(int); }_timer_manage_t; static struct _timer_manage timer_manage; static void* timer_routine(void*) { int i; while(true) { for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 0) { continue; } timer_manage.timer_info[i].elapse++; if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) { timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); } } usleep(1000 * TIMER_UNIT); } return NULL; } static int init_mul_timer() { static bool s_is_init = false; if(s_is_init == true) { return 0; } memset(&timer_manage, 0, sizeof(struct _timer_manage)); pthread_t pid; pthread_create(&pid, NULL, timer_routine, NULL); s_is_init = true; return 1; } static int set_a_timer(int interval, void (* timer_proc)(void* param), void* param) { init_mul_timer(); int i; if(timer_proc == NULL || interval <= 0) { return (-1); } for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 1) { continue; } memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); timer_manage.timer_info[i].timer_proc = timer_proc; timer_manage.timer_info[i].param = param; timer_manage.timer_info[i].interval = interval; timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].state = 1; break; } if(i >= MAX_TIMER_CNT) { ASSERT(false); return (-1); } return (i); } typedef void (*EXPIRE_ROUTINE)(void* arg); EXPIRE_ROUTINE s_expire_function; static c_fifo s_real_timer_fifo; static void* real_timer_routine(void*) { char dummy; while(1) { if(s_real_timer_fifo.read(&dummy, 1) > 0) { if(s_expire_function)s_expire_function(0); } else { ASSERT(false); } } return 0; } static void expire_real_timer(int sigo) { char dummy = 0x33; if(s_real_timer_fifo.write(&dummy, 1) <= 0) { ASSERT(false); } } void start_real_timer(void (*func)(void* arg)) { if(NULL == func) { return; } s_expire_function = func; signal(SIGALRM, expire_real_timer); struct itimerval value, ovalue; value.it_value.tv_sec = 0; value.it_value.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; value.it_interval.tv_sec = 0; value.it_interval.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; setitimer(ITIMER_REAL, &value, &ovalue); static pthread_t s_pid; if(s_pid == 0) { pthread_create(&s_pid, NULL, real_timer_routine, NULL); } } unsigned int get_cur_thread_id() { return (unsigned long)pthread_self(); } void register_timer(int milli_second,void func(void* param), void* param) { set_a_timer(milli_second/TIMER_UNIT,func, param); } long get_time_in_second() { return time(NULL); /* + 8*60*60*/ } T_TIME get_time() { T_TIME ret = {0}; struct tm *fmt; time_t timer; timer = get_time_in_second(); fmt = localtime(&timer); ret.year = fmt->tm_year + 1900; ret.month = fmt->tm_mon + 1; ret.day = fmt->tm_mday; ret.hour = fmt->tm_hour; ret.minute = fmt->tm_min; ret.second = fmt->tm_sec; return ret; } T_TIME second_to_day(long second) { T_TIME ret = {0}; struct tm *fmt; fmt = localtime(&second); ret.year = fmt->tm_year + 1900; ret.month = fmt->tm_mon + 1; ret.day = fmt->tm_mday; ret.hour = fmt->tm_hour; ret.minute = fmt->tm_min; ret.second = fmt->tm_sec; return ret; } void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) { pthread_create((pthread_t*)thread_id, (pthread_attr_t const*)attr, start_routine, arg); } void thread_sleep(unsigned int milli_seconds) { usleep(milli_seconds * 1000); } typedef struct { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; }__attribute__((packed))FileHead; typedef struct{ unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompress; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; unsigned int biRedMask; unsigned int biGreenMask; unsigned int biBlueMask; }__attribute__((packed))Infohead; int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) { FileHead bmp_head; Infohead bmp_info; int size = width * height * 2; //initialize bmp head. bmp_head.bfType = 0x4d42; bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; bmp_head.bfOffBits = bmp_head.bfSize - size; //initialize bmp info. bmp_info.biSize = 40; bmp_info.biWidth = width; bmp_info.biHeight = height; bmp_info.biPlanes = 1; bmp_info.biBitCount = 16; bmp_info.biCompress = 3; bmp_info.biSizeImage = size; bmp_info.biXPelsPerMeter = 0; bmp_info.biYPelsPerMeter = 0; bmp_info.biClrUsed = 0; bmp_info.biClrImportant = 0; //RGB565 bmp_info.biRedMask = 0xF800; bmp_info.biGreenMask = 0x07E0; bmp_info.biBlueMask = 0x001F; //copy the data FILE *fp; if(!(fp=fopen(filename,"wb"))) { return -1; } fwrite(&bmp_head, 1, sizeof(FileHead),fp); fwrite(&bmp_info, 1, sizeof(Infohead),fp); //fwrite(data, 1, size, fp);//top <-> bottom for (int i = (height - 1); i >= 0; --i) { fwrite(&data[i * width * 2], 1, width * 2, fp); } fclose(fp); return 0; } c_fifo::c_fifo() { m_head = m_tail = 0; m_read_sem = malloc(sizeof(sem_t)); m_write_mutex = malloc(sizeof(pthread_mutex_t)); sem_init((sem_t*)m_read_sem, 0, 0); pthread_mutex_init((pthread_mutex_t*)m_write_mutex, 0); } int c_fifo::read(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; while(i < len) { if (m_tail == m_head) {//empty sem_wait((sem_t*)m_read_sem); continue; } *pbuf++ = m_buf[m_head]; m_head = (m_head + 1) % FIFO_BUFFER_LEN; i++; } if(i != len) { ASSERT(false); } return i; } int c_fifo::write(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; int tail = m_tail; pthread_mutex_lock((pthread_mutex_t*)m_write_mutex); while(i < len) { if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) {//full, clear data has been written; m_tail = tail; log_out("Warning: fifo full\n"); pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); return 0; } m_buf[m_tail] = *pbuf++; m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; i++; } pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); if(i != len) { ASSERT(false); } else { sem_post((sem_t*)m_read_sem); } return i; } #endif #endif #ifdef GUILITE_ON #if (defined __none_os__) || ((!defined _WIN32) && (!defined WIN32) && (!defined _WIN64) && (!defined WIN64) && (!defined __linux__) && (!defined __APPLE__)) #include static void(*do_assert)(const char* file, int line); static void(*do_log_out)(const char* log); void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) { do_assert = my_assert; do_log_out = my_log_out; } void _assert(const char* file, int line) { if(do_assert) { do_assert(file, line); } while(1); } void log_out(const char* log) { if (do_log_out) { do_log_out(log); } } long get_time_in_second() { return 0; } T_TIME second_to_day(long second) { T_TIME ret = {0}; return ret; } T_TIME get_time() { T_TIME ret = {0}; return ret; } void start_real_timer(void (*func)(void* arg)) { log_out("Not support now"); } void register_timer(int milli_second, void func(void* ptmr, void* parg)) { log_out("Not support now"); } unsigned int get_cur_thread_id() { log_out("Not support now"); return 0; } void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) { log_out("Not support now"); } extern "C" void delay_ms(unsigned short nms); void thread_sleep(unsigned int milli_seconds) {//MCU alway implemnet driver code in APP. delay_ms(milli_seconds); } int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) { log_out("Not support now"); return 0; } c_fifo::c_fifo() { m_head = m_tail = 0; m_read_sem = m_write_mutex = 0; } int c_fifo::read(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; while(i < len) { if (m_tail == m_head) {//empty continue; } *pbuf++ = m_buf[m_head]; m_head = (m_head + 1) % FIFO_BUFFER_LEN; i++; } if(i != len) { ASSERT(false); } return i; } int c_fifo::write(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; int tail = m_tail; while(i < len) { if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) {//full, clear data has been written; m_tail = tail; log_out("Warning: fifo full\n"); return 0; } m_buf[m_tail] = *pbuf++; m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; i++; } if(i != len) { ASSERT(false); } return i; } #endif #endif #ifdef GUILITE_ON #if (defined _WIN32) || (defined WIN32) || (defined _WIN64) || (defined WIN64) #include #include #include #include #include #include #define MAX_TIMER_CNT 10 #define TIMER_UNIT 50//ms static void(*do_assert)(const char* file, int line); static void(*do_log_out)(const char* log); void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) { do_assert = my_assert; do_log_out = my_log_out; } void _assert(const char* file, int line) { static char s_buf[192]; if (do_assert) { do_assert(file, line); } else { memset(s_buf, 0, sizeof(s_buf)); sprintf_s(s_buf, sizeof(s_buf), "vvvvvvvvvvvvvvvvvvvvvvvvvvvv\n\nAssert@ file = %s, line = %d\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", file, line); OutputDebugStringA(s_buf); printf("%s", s_buf); fflush(stdout); assert(false); } } void log_out(const char* log) { if (do_log_out) { do_log_out(log); } else { printf("%s", log); fflush(stdout); OutputDebugStringA(log); } } typedef struct _timer_manage { struct _timer_info { int state; /* on or off */ int interval; int elapse; /* 0~interval */ void (* timer_proc) (void* param); void* param; }timer_info[MAX_TIMER_CNT]; void (* old_sigfunc)(int); void (* new_sigfunc)(int); }_timer_manage_t; static struct _timer_manage timer_manage; DWORD WINAPI timer_routine(LPVOID lpParam) { int i; while(true) { for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 0) { continue; } timer_manage.timer_info[i].elapse++; if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) { timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); } } Sleep(TIMER_UNIT); } return 0; } static int init_mul_timer() { static bool s_is_init = false; if(s_is_init == true) { return 0; } memset(&timer_manage, 0, sizeof(struct _timer_manage)); DWORD pid; CreateThread(0, 0, timer_routine, 0, 0, &pid); s_is_init = true; return 1; } static int set_a_timer(int interval, void (* timer_proc) (void* param), void* param) { init_mul_timer(); int i; if(timer_proc == 0 || interval <= 0) { return (-1); } for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 1) { continue; } memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); timer_manage.timer_info[i].timer_proc = timer_proc; timer_manage.timer_info[i].param = param; timer_manage.timer_info[i].interval = interval; timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].state = 1; break; } if(i >= MAX_TIMER_CNT) { ASSERT(false); return (-1); } return (i); } typedef void (*EXPIRE_ROUTINE)(void* arg); EXPIRE_ROUTINE s_expire_function; static c_fifo s_real_timer_fifo; static DWORD WINAPI fire_real_timer(LPVOID lpParam) { char dummy; while(1) { if(s_real_timer_fifo.read(&dummy, 1) > 0) { if(s_expire_function)s_expire_function(0); } else { ASSERT(false); } } return 0; } /*Win32 desktop only static void CALLBACK trigger_real_timer(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR) { char dummy = 0x33; s_real_timer_fifo.write(&dummy, 1); } */ static DWORD WINAPI trigger_real_timer(LPVOID lpParam) { char dummy = 0x33; while (1) { s_real_timer_fifo.write(&dummy, 1); Sleep(REAL_TIME_TASK_CYCLE_MS); } return 0; } void start_real_timer(void (*func)(void* arg)) { if(0 == func) { return; } s_expire_function = func; //timeSetEvent(REAL_TIME_TASK_CYCLE_MS, 0, trigger_real_timer, 0, TIME_PERIODIC);//Win32 desktop only static DWORD s_pid; if(s_pid == 0) { CreateThread(0, 0, trigger_real_timer, 0, 0, &s_pid); CreateThread(0, 0, fire_real_timer, 0, 0, &s_pid); } } unsigned int get_cur_thread_id() { return GetCurrentThreadId(); } void register_timer(int milli_second,void func(void* param), void* param) { set_a_timer(milli_second/TIMER_UNIT,func, param); } long get_time_in_second() { return (long)time(0); } T_TIME get_time() { T_TIME ret = {0}; SYSTEMTIME time; GetLocalTime(&time); ret.year = time.wYear; ret.month = time.wMonth; ret.day = time.wDay; ret.hour = time.wHour; ret.minute = time.wMinute; ret.second = time.wSecond; return ret; } T_TIME second_to_day(long second) { T_TIME ret; ret.year = 1999; ret.month = 10; ret.date = 1; ret.second = second % 60; second /= 60; ret.minute = second % 60; second /= 60; ret.hour = (second + 8) % 24;//China time zone. return ret; } void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) { DWORD pid = 0; CreateThread(0, 0, LPTHREAD_START_ROUTINE(start_routine), arg, 0, &pid); *thread_id = pid; } void thread_sleep(unsigned int milli_seconds) { Sleep(milli_seconds); } #pragma pack(push,1) typedef struct { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; }FileHead; typedef struct { unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompress; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; unsigned int biRedMask; unsigned int biGreenMask; unsigned int biBlueMask; }Infohead; #pragma pack(pop) int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) { FileHead bmp_head; Infohead bmp_info; int size = width * height * 2; //initialize bmp head. bmp_head.bfType = 0x4d42; bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; bmp_head.bfOffBits = bmp_head.bfSize - size; //initialize bmp info. bmp_info.biSize = 40; bmp_info.biWidth = width; bmp_info.biHeight = height; bmp_info.biPlanes = 1; bmp_info.biBitCount = 16; bmp_info.biCompress = 3; bmp_info.biSizeImage = size; bmp_info.biXPelsPerMeter = 0; bmp_info.biYPelsPerMeter = 0; bmp_info.biClrUsed = 0; bmp_info.biClrImportant = 0; //RGB565 bmp_info.biRedMask = 0xF800; bmp_info.biGreenMask = 0x07E0; bmp_info.biBlueMask = 0x001F; //copy the data FILE *fp; if (!(fp = fopen(filename, "wb"))) { return -1; } fwrite(&bmp_head, 1, sizeof(FileHead), fp); fwrite(&bmp_info, 1, sizeof(Infohead), fp); //fwrite(data, 1, size, fp);//top <-> bottom for (int i = (height - 1); i >= 0; --i) { fwrite(&data[i * width * 2], 1, width * 2, fp); } fclose(fp); return 0; } c_fifo::c_fifo() { m_head = m_tail = 0; m_read_sem = CreateSemaphore(0, // default security attributes 0, // initial count 1, // maximum count 0); // unnamed semaphore m_write_mutex = CreateMutex(0, false, 0); } int c_fifo::read(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; while (i < len) { if (m_tail == m_head) {//empty WaitForSingleObject(m_read_sem, INFINITE); continue; } *pbuf++ = m_buf[m_head]; m_head = (m_head + 1) % FIFO_BUFFER_LEN; i++; } if (i != len) { ASSERT(false); } return i; } int c_fifo::write(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; int tail = m_tail; WaitForSingleObject(m_write_mutex, INFINITE); while (i < len) { if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) {//full, clear data has been written; m_tail = tail; log_out("Warning: fifo full\n"); ReleaseMutex(m_write_mutex); return 0; } m_buf[m_tail] = *pbuf++; m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; i++; } ReleaseMutex(m_write_mutex); if (i != len) { ASSERT(false); } else { ReleaseSemaphore(m_read_sem, 1, 0); } return i; } #endif #endif #ifdef GUILITE_ON DIALOG_ARRAY c_dialog::ms_the_dialogs[SURFACE_CNT_MAX]; c_keyboard c_edit::s_keyboard; static c_keyboard_button s_key_0, s_key_1, s_key_2, s_key_3, s_key_4, s_key_5, s_key_6, s_key_7, s_key_8, s_key_9; static c_keyboard_button s_key_A, s_key_B, s_key_C, s_key_D, s_key_E, s_key_F, s_key_G, s_key_H, s_key_I, s_key_J; static c_keyboard_button s_key_K, s_key_L, s_key_M, s_key_N, s_key_O, s_key_P, s_key_Q, s_key_R, s_key_S, s_key_T; static c_keyboard_button s_key_U, s_key_V, s_key_W, s_key_X, s_key_Y, s_key_Z; static c_keyboard_button s_key_dot, s_key_caps, s_key_space, s_key_enter, s_key_del, s_key_esc, s_key_num_switch; WND_TREE g_key_board_children[] = { //Row 1 {&s_key_Q, 'Q', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_W, 'W', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_E, 'E', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_R, 'R', 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_T, 'T', 0, POS_X(4), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_Y, 'Y', 0, POS_X(5), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_U, 'U', 0, POS_X(6), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_I, 'I', 0, POS_X(7), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_O, 'O', 0, POS_X(8), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_P, 'P', 0, POS_X(9), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, //Row 2 {&s_key_A, 'A', 0, ((KEY_WIDTH / 2) + POS_X(0)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_S, 'S', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_D, 'D', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_F, 'F', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_G, 'G', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_H, 'H', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_J, 'J', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_K, 'K', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_L, 'L', 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, //Row 3 {&s_key_caps, 0x14, 0, POS_X(0), POS_Y(2), CAPS_WIDTH, KEY_HEIGHT}, {&s_key_Z, 'Z', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_X, 'X', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_C, 'C', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_V, 'V', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_B, 'B', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_N, 'N', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_M, 'M', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_del,0x7F, 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(2), DEL_WIDTH, KEY_HEIGHT}, //Row 4 {&s_key_esc, 0x1B, 0, POS_X(0), POS_Y(3), ESC_WIDTH, KEY_HEIGHT}, {&s_key_num_switch, 0x90, 0, POS_X(2), POS_Y(3), SWITCH_WIDTH, KEY_HEIGHT}, {&s_key_space, ' ', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(3), SPACE_WIDTH, KEY_HEIGHT}, {&s_key_dot, '.', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(3), DOT_WIDTH, KEY_HEIGHT}, {&s_key_enter, '\n', 0, POS_X(8), POS_Y(3), ENTER_WIDTH, KEY_HEIGHT}, {0,0,0,0,0,0,0} }; WND_TREE g_number_board_children[] = { {&s_key_1, '1', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_2, '2', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_3, '3', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_4, '4', 0, POS_X(0), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_5, '5', 0, POS_X(1), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_6, '6', 0, POS_X(2), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_7, '7', 0, POS_X(0), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_8, '8', 0, POS_X(1), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_9, '9', 0, POS_X(2), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_esc,0x1B, 0, POS_X(0), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, {&s_key_0, '0', 0, POS_X(1), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, {&s_key_dot,'.', 0, POS_X(2), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, {&s_key_del, 0x7F, 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, {&s_key_enter,'\n', 0, POS_X(3), POS_Y(2), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, {0,0,0,0,0,0,0} }; #endif ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # Welcome to GUI-lite

Logo

The smallest header-only GUI library (4 KLOC) for all platforms.

Why GuiLite

- [中文](README_zh.md) ## Lightweight - ✂️Small: 4,000+ lines of C++ code, zero dependency, header-only(GuiLite.h) - ⚡Fast: High Rendering performance, even work on MCU - 👫🏻Compatible: Work smoothly with 3rd party frameworks(Qt/MFC/Winform/Cocoa/Web) - ⚙️️Hardware Minimum Requirements: | Processor | Disk/ROM space | Memory | | --- | --- | --- | | 24 MHZ | 29 KB | 9 KB | ## Cross platform - Supported OSes: iOS/macOS/WatchOS, Android, Linux, Windows, RTOS... or **MCU without OS** - Supported languages: C/C++, Swift, Java, Javascript, C#, Golang... - Supported 3rd party libraries: Qt, MFC, Winforms, CoCoa... ## Hero features - ☁️Cloud + IoT Solution: master your IoT business all over the world - 🔣Multi-language, supports UTF-8;📀Playback Video - 🔨[Toolkit](https://github.com/idea4good/GuiLiteToolkit) for building font/image resources - 📐[Layout GUI WYSIWYG](https://github.com/idea4good/GuiLitePreviewer) - 📊Code Telemetry and Analysis in real time - 📦Supports 3D and [Web](https://github.com/idea4good/GuiLiteWeb) - 🐋Run in docker with a single command: `sudo docker run -it --privileged -v /dev:/dev-share idea4good/gui-lite:latest bash /run.sh` ## Easy to learn and support Even a C beginner could master GUI-lite quickly. The source code only uses basic C++ features (class, virtual function). We chose C++ as it could make the code size significantly smaller and easier to read. - 📚Documentation - [How to use GUI-lite?](documents/HowToUse.md) - [Design specification](documents/HowToWork.md) - [How to Layout widgets?](documents/HowLayoutWork.md) - [How to build unicode font/bitmap resource?](https://github.com/idea4good/GuiLiteToolkit) - [How to switch theme?](https://github.com/idea4good/GuiLiteSamples/blob/master/HostMonitor/UIcode/source/resource/resource.cpp) - [How to dispatch messages?](documents/HowMessageWork.md) - [UML chart of GUI-lite core](documents/UML.md) - 📈Learning steps 1. Build GUI-lite library 2. Build/Debug HelloXXX demos 3. Read/Modify `HelloXXX/UIcode/UIcode.cpp` code 4. Read/Modify `widgets` code 5. Read/Modify `core` code 6. Build your GUI framework - 📞[Reach out us](#community-channel) if you have any questions you are welcomed to our developer family. - 🀄️[Mirror repository in China](https://gitee.com/idea4good/GuiLite) ## Demo wall - Zero dependency, 100% build pass & runnable - Click the demo you like, and run it on your hardware - Most of the demos have about 100 lines of UI code, the code repository is [GuiLiteSamples](https://github.com/idea4good/GuiLiteSamples) --- ### MCU platform ---

3D on STM32

Wave on STM32

Particle on STM32

Star on STM32

3D wave on STM32

Keyboard on STM32

Mario on STM32

3D circle on STM32

3D donut on STM32

Timer

Molecule move

Pendulum effect
--- ### IoT feature ---

Monitor IoT device on cloud

Code Telemetry & Analysis in real time

Track IoT device over the world
--- ### Multi-language, Design tool and video ---

Lattice Font

Freetype Font

Layout GUI

Render JPG file quickly

Play video with FFmpeg
--- ### Widgets & Controller ---

Emulate Windows UI

Scroll widget

How to use widgets

3D Nets on Windows/Linux

Transparent dialog

Swipe view
--- ### Cross platform ---

HostMonitor on Windows

HostMonitor on Mac

HostMonitor on Android

HostMonitor on Windows Mixed Reality

HostMonitor on Linux

3D on Web

3D on Web

HostMonitor on iPhone

How display work
--- ### Apple platform ---

3D on Apple Watch

Wave on Apple Watch

Particle on iPhone
## 📞Community Channel Thanks for the help from the community, you all make GUI-lite better! And welcome to any new friend to join us. - [**@Twitter**](https://twitter.com/idea4good) - QQ group: ================================================ FILE: README_zh.md ================================================ # 歡迎蒞臨 GUI-lite

Logo

大道至簡 - 4千行/仅头文件/全平台GUI库

Why GuiLite

## 輕-快-容 - ✂️轻量: 4千行C++代码,0依赖,单一头文件库(GuiLite.h) - ⚡超快: 高效渲染,单片机上也能流畅运行 - 👫🏻兼容: 完美兼容第3方GUI框架(Qt/MFC/Winform/Cocoa/Web),现有Qt/MFC代码可以继续使用 - ⚙️️最低硬件要求: | Processor | Disk/ROM space | Memory | | --- | --- | --- | | 24 MHZ | 29 KB | 9 KB | ## 跨平臺 - 支持的操作系统:iOS/macOS/WatchOS,Android,Linux(ARM/x86-64),Windows(包含VR),RTOS... 甚至**无操作系统的单片机** - 支持的开发语言: C/C++, Swift, Java, Javascript, C#, Golang... - 支持的第3方库:Qt, MFC, Winforms, CoCoa... ## 實用的功能 - ☁️完美的“云” + “物联网”解决方案:让你轻松驾驭全球IoT业务 - 🔣支持多语言,采用 UTF-8 编码;📀支持视频播放 - 🔨[资源制作工具](https://github.com/idea4good/GuiLiteToolkit)为你定制自己的字体/图片资源 - 📐[所见即所得的GUI布局工具](https://github.com/idea4good/GuiLitePreviewer) - 📊编译活跃度统计,及实时分析 - 📦支持3D & [Web](https://github.com/idea4good/GuiLiteWeb) - 🐋支持Docker,一条命令启动Docker: `sudo docker run -it --privileged -v /dev:/dev-share idea4good/gui-lite:latest bash /run.sh` ## 易學習和全面的技術支持 即使是C语言的初学者,也可以很快掌握GUI-lite;代码只使用C++的基本特性(类和虚函数),选择C++语言,能让代码体积更小,更易阅读。 - 📚开发文档 - [如何使用GUI-lite?](documents/HowToUse.md) - [软件设计说明](documents/HowToWork-cn.md) - [如何布局UI?](documents/HowLayoutWork.md) - [如何制作多种文字/位图资源?](https://github.com/idea4good/GuiLiteToolkit) - [如何“换肤”?](https://github.com/idea4good/GuiLiteSamples/blob/master/HostMonitor/UIcode/source/resource/resource.cpp) - [如何传递消息?](documents/HowMessageWork.md) - [核心UML示意图](documents/UML.md) - 📈学习方法 1. 编译GUI-lite库 2. 编译、调试:HelloXXX实例程序 3. 研读、修改100+行的`HelloXXX/UIcode/UIcode.cpp`源代码 4. 研读`widgets`目录下的代码 5. 研读`core`目录下的代码 6. 扩展/开发自己的GUI库 - 📞遇到任何问题,都可以[联系我们](#社区交流),也欢迎加入我们的开发者大家庭 - 🌐[码云Gitee快速链接](https://gitee.com/idea4good/GuiLite) ## Demo展示墻 - 0依赖,100%编译通过,可直接运行 - 点击你喜欢的实例,并运行在你的硬件上面 - 大部分demo的UI代码只有100行左右,代碼庫在[GuiLiteSamples](https://github.com/idea4good/GuiLiteSamples) --- ### 單片機平臺 ---

開發群🔑:875721211

3D on STM32

Wave on STM32

Particle on STM32

Star on STM32

3D wave on STM32

Keyboard on STM32

Mario on STM32

3D circle on STM32

3D donut on STM32

Timer

Molecule move

Pendulum effect
--- ### IoT 功能 ---

Monitor IoT device on cloud

Code Telemetry & Analysis in real time

Track IoT device over the world
--- ### 多語言,設計工具及視頻 ---

Lattice Font

Freetype Font

Layout GUI

Render JPG file quickly

Play video with FFmpeg
--- ### UI 控件實作 ---

Emulate Windows UI

Scroll widget

How to use widgets

3D Nets on Windows/Linux

Transparent dialog

Swipe view
--- ### 跨平臺實作 ---

HostMonitor on Windows

HostMonitor on Mac

HostMonitor on Android

HostMonitor on Windows Mixed Reality

HostMonitor on Linux

3D on Web

3D on Web

HostMonitor on iPhone

How display work
--- ### 蘋果平臺 ---

3D on Apple Watch

Wave on Apple Watch

Particle on iPhone
## 📞社區交流 - 感谢开发者群的所有同学,是你们塑造了今天的GUI-lite!也欢迎新的大神/小白加入我们。 - 开发者QQ ================================================ FILE: documents/HowLayoutWork.md ================================================ # How to layout widgets for GuiLiteSamples::HostMonitor? All widgets were described by struct WND_TREE and ?.xml.cpp files ## How to layout slide group? ![Layout slides group](layout_slide_group.png) ## How to layout single slide? ![Layout single slide](layout_single_slide.png) ## How to layout dialog? ![Layout dialog](layout_dialog.png) ================================================ FILE: documents/HowMessageWork.md ================================================ # How messages work for GuiLiteSamples::HostMonitor? ## How real time message(draw waves) work? ![Callstack for drawing waves](draw_wav.png) ## How click button message work? ![Callstack for clicking button](click_button.png) ## How left/right flip message work? ![Callstack for fliping slides](flip.png) ================================================ FILE: documents/HowToUse.md ================================================ # How to use GuiLite? - For GuiLite user: You could copy GuiLite.h in your application - For GuiLite developer: You could get well-organized source code, and develop it on any platform(Windows/Linux/Apple) # For GuiLite user GuiLite is a header-only library, so it should be straightforward to integrate into your application. UIcode.cpp: ```c++ #define GUILITE_ON // Do not define this macro upon GuiLite.h once more #include "GuiLite.h" // your code here: ``` # For GuiLite developer ## Build GuiLite library for Windows? Prerequisite: Windows & Visul Studio 2013/2015/2017/2019 - Open "GuiLite.sln" by Visual Studio - Click `Build Solution` - Output here: GuiLite\workspace\Debug(Release)\GuiLite.lib FAQ: Error when open GuiLite project with Visual Studio, reconfigure the project to match your computer like this: ![vs-configure](vs-configure.jpg) ## Build GuiLite library for iOS/Mac and Linux(amd64) & raspberry pi? ```bash cd GuiLite/workspace cmake . make # Output here: GuiLite/workspace/libGuiLite.a ``` ## Build GuiLite library for ARM Linux? ### Prerequisite: Install cross compiler: ```bash # For ARM32: sudo apt-get install g++-arm-linux-gnueabi gcc-arm-linux-gnueabi # For ARM64: sudo apt-get install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu ``` ### Build ```bash cd GuiLite/workspace # For ARM32: cmake -D CMAKE_C_COMPILER="/usr/bin/arm-linux-gnueabi-gcc" -D CMAKE_CXX_COMPILER="/usr/bin/arm-linux-gnueabi-g++" . # For ARM64: cmake -D CMAKE_C_COMPILER="/usr/bin/aarch64-linux-gnu-gcc" -D CMAKE_CXX_COMPILER="/usr/bin/aarch64-linux-gnu-g++" . make ``` Output here: GuiLite/workspace/libGuiLite.a ## How to build GuiLite library for any MCU? ### Prerequisite: Install Keil uvsion 5.6 or above. ### Build - Open `GuiLite/workspace/GuiLite.uvprojx` with Keil uvsion. - Implement function(e.g, thread_sleep) in `core\src\adapter\api_unknow.cpp` to meet your need. - Choose your Device type(Default: STM32F103ZE) from option for target. - Build GuiLite. - Output here: GuiLite/workspace/Objects/GuiLite.lib ## Build header-only GuiLite.h? ```bash cd GuiLite/src ./GenerateGuiLite.h.sh ``` ================================================ FILE: documents/HowToWork-cn.md ================================================ # GuiLite设计原理及代码注释 - [基本原理](#基本原理) - [扩展方法](#扩展方法) - [代码目录结构](#代码目录结构) - [界面元素管理](#界面元素管理) - [图形绘制](#图形绘制) - [文件注释](#文件注释) - [函数注释](#函数注释) - [速成路线图](#速成路线图) *** ## 基本原理 GuiLite只做两个工作:界面元素管理和图形绘制。 界面管理包括: - 添加/删除界面元素(例如:按钮,标签,对话框等控件),设置对应的文字及位置信息 - 用户输入消息传递:根据用户输入寻找受影响的界面元素,并回调响应的处理的处理函数 - 用户自定义消息传递:用户可以自定义消息响应函数,并自主产生消息;当消息产生时,对应的响应函数会被调用 图形绘制包括: - 基本的点线绘制,例如:画点,矩形,横线,竖线等 - 设置绘制图层,如果需要多个图层,在基本点线绘制时,需要给出图层的索引值 - 图层处理,在图层界面发生变化的时候(例如:打开/关闭对话框),GuiLite将决定各个图层上的像素点,哪个会被最终显示在屏幕上 👉注意:图形绘制不依赖界面管理,可以独立的存在,例如,在资源有限的单片机环境,有时候不需要界面元素管理,而直接进行图形,文字的绘制。 ## 扩展方法 GuiLite只给出了基本控件(例如:按钮,标签,键盘,选择框)的实现方法,旨在说明控件的实现方法。对于扩展控件,可以选择下面的方式: - 如果开发者需要调整基本控件的细节,可以直接在源代码中修改 - 如果开发者需要构建全新的控件,可以参考基本控件的实现方法,重新实现 对于扩展绘制,例如:画圆,画曲线,可以直接在surface.cpp文件中添加响应的函数接口。 ## 代码目录结构 core: - 实现了底层绘制,图层管理和消息传递 - adapter实现了各个平台(例如:Windows, Linux,Android,iOS,macOS,未知OS或无OS)的封装。 widgets: - 实现了各种常规控件(例如:按钮,标签,键盘,波形)及容器(例如:视窗,对话框,滑动页面),开发者可以根据自己的需要,直接在相应的代码上进行修改或重绘,开发出有自己风格,特色的界面 - 实现了用户的手势识别(例如:手指滑动,鼠标按下/释放)的消息传递,将用户的输入信息传递到整个GUI体系树中,并调用相应的响应回调函数;开发者可以根据自己的需要添加/修改响应回调函数。 ## 界面元素管理 界面元素管理包括:对所有控件(button,spinbox, lable, keyboard),容器(dialog, view)管理;具体的管理方法是在用户调用connect函数时,会把所有的界面元素连接起来,从而实现对所有界面元素的遍历/添加/删除等操作。这些链接看起来像一棵树,对界面元素的遍历,就是对这棵树的遍历 比如:当你按下一个dialog的button时,手指的位置信息(x,y)会被传入树的根部(root),然后从root开始寻找,哪个dialog被点中,dialog的哪个button被点中,并调用buton被点中的回调函数,用于作相应处理(一般会进行button的状态修改及重绘工作) ### 界面元素如何创建 所有界面元素都继承自c_wnd类的对象,对象被实例化时,也就完成了界面元素的创建;但此时的界面元素是孤独的,与其他界面元素没有形成联系(没有父母,没有兄弟姐妹) ### 界面元素如何被管理 新创建的界面元素纳入管理的过程,就是为其添加父母,兄弟姐妹的过程。使用的函数接口为connect();从此该界面元素会跟其他界面元素一样,纳入一棵树中,并随之响应用户可能的点击操作。 当需要删掉该界面元素时,使用disconnect();从此该界面元素会断绝所有的父子关系,从树上摘下来,不再响应用户的触控操作;但对象本身不会被销毁。典型应用场景:软键盘的创建/退出。 ## 图形绘制 图形绘制包括: 绘制方法和图层管理。 - 点绘制是线/面/位图绘制的基础,若干个点的绘制,形成点面及位图 - 图层管理,则是管理多个界面元素的遮挡关系,系统默认支持3层遮挡关系,这3个层次可以为:视图背景层,对话框层,keyboard/spinbox控件层。 ### 绘制方法 请参看文件bitmap.cpp和surface.cpp中的draw_xxx()函数。 为了发挥GPU的加速功能,也可以通过改写draw_xxx/fill_xxx函数,使用GPU特性,来提升绘制效率。 ### 图层管理 ![Graphic layer](GraphicLayer.png)![GuiLiteGraphic](GuiLiteGraphic.gif) - display层:该层对应了物理显存,display层决定了一个显示终端的最终显示效果;通常系统中至少有一个display层。 - surface层:该层属于display层的一个部分;它为左右滑动而存在,每一张滑动页面均对应了一个surface层;surface层决定了一个滑动页面的最终显示效果;通常1个display层会对应多个surface层。 - frame层:该层属于surface层的一个部分;它现实叠加界面元素而存在。 ## 文件注释 | core 重要程度/文件名称 | 代码简介 | 推荐学习时间 | | --- | --- | --- | | ★★★ wnd.h | UI元素的基本类,定义所有的UI元素信息、绘制及管理办法 | 1.5小时 | | ★★ display.h | 生成显示设备,设定surface的数目,一个surface对应一个滑动页面 | 0.5小时 | | word.h | 显示文字 | < 1小时 | | image.h | 绘制位图,支持16 bits和32 bits | < 0.5小时 | | rect.h | UI元素的位置信息 | < 0.5小时 | | api_linux.cpp | Linux适配层 | < 0.5小时 | | api_win.cpp | Window适配层 | < 0.5小时 | | api_unknow.cpp | 无OS或其他OS适配层 | < 0.5小时 | *** | widgets 难度/文件名称 | 代码简介 | 推荐学习时间 | | --- | --- | --- | | label.h | 标签控件的绘制 | < 0.5小时 | | button.h | 按钮控件的绘制及用户点击响应函数 | < 0.5小时 | | table.h | Table控件的绘制 | < 0.5小时 | | dialog.h | 对话框的绘制及管理方法 | < 0.5小时 | | ★ keyboard.h | 键盘控件的绘制及用户点击响应函数 | 0.5小时 | | ★★ list_box.h | List控件的绘制及用户点击响应函数 | 1.5小时 | | ★★ spinbox.h | Spinbox控件的绘制及用户点击响应函数 | 1.5小时 | | ★★ edit.h | Edit控件的绘制及用户点击响应函数 | 1.5小时 | | ★ slide_group.h | 多屏GUI的实现,以及用来切换屏幕的划屏操作 | 1.5小时 | | ★★★ wave_buffer.h | 波形数据的缓冲管理 | 1.5小时 | | ★★★ wave_ctrl.h | 它通过波形数据,绘制实时的波形控件 | 1.5小时 | ## 函数注释 | 函数名称 | display.h::c_display 函数接口注释 | | --- | --- | | c_display | c_display构造函数。phy_fb:物理framebuffer指针;display_width:物理显示器宽度;display_height:物理显示器高度;surface_width:surface宽度;surface_height:surface高度;color_bytes:颜色深度;surface_cnt:surface个数/滑动页面的个数;gfx_op:外部绘制接口,用以适配非framebuffer的渲染方式,如果该值不为空,surface在作底层渲染的时候,会调用该接口 | | alloc_surface | 分配surface/滑动页面。usr: 用户ID;max_zorder:该surface所拥有的图层数量| | merge_surface | 横向组合两个surface,多用于滑动surface。s0:源surface 0;s1:源surface 1,x0:源surface 0的起始点x坐标;x1:源surface 1的起始点x坐标;y0:源surface 0的起始点y坐标;y1:源surface 1的起始点y坐标;offset:横向组合的偏移距离 | | get_updated_fb | 获取该display的framebuffer指针,常用来将GUI显示在任意需要的地方。widght:用来获取framebuffer的宽度;height:用来获取framebuffer的高度;force_update:是否需要强制更新framebuffer的内容,如果不需要强制更新,且framebuffer没法发生变化,将返回NULL | | snap_shot | 生成当前显示的快照,并输出到bitmap文件。file_name:快照文件的名称 | *** | 函数名称 | display.h::c_surface 函数接口注释 | | --- | --- | | c_surface | c_surface构造函数。 display:surface所属于的display;width:surface的宽度;height:surface的高度;color_bytes:颜色深度| | set_surface | 设置surface。wnd_root:使用者者ID,通常为root window,其子窗口自动获得该surface的使用权。 max_z_order:该surface拥有的图层数量 | | draw_pixel | 渲染一个像素点。x:像素点坐标x;y:像素点坐标y;rgb:像素颜色;z_order:像素所在的图层 | | draw_pixel_on_fb | 渲染一个像素点 - 底层渲染。x:像素点坐标x;y:像素点坐标y;rgb:像素颜色 | | fill_rect | 填充一个矩形。 x0:矩形左上角的坐标x;y0:矩形左上角的坐标y;x1:矩形右下角的坐标x;y1:矩形右下角的坐标y;rgb:矩形的颜色;z_order:矩形所在的图层| | fill_rect_on_fb | 填充一个矩形 - 底层渲染。 x0:矩形左上角的坐标x;y0:矩形左上角的坐标y;x1:矩形右下角的坐标x;y1:矩形右下角的坐标y;rgb:矩形的颜色 | | get_pixel | 获取指定位置的像素点的颜色值。x:位置坐标x;y:位置坐标y;z_order:位置坐标z(图层坐标) | | draw_hline | 渲染一条横线。x0:横线的左边起始坐标x;x1:横线的右边结尾坐标x;y:横线的纵向坐标y | | draw_vline | 渲染一条竖线。x:竖线的横向坐标:x;y0:竖线的上起始坐标y;y1:竖线的下结尾坐标y | | draw_line | 渲染普通直线。x1:直线左端点的坐标x;y1:直线左端点的坐标y;x2:直线右端点坐标x;y2:直线右端点坐标y | | draw_rect | 渲染矩形。x0:矩形左上角的坐标x;y0:矩形左上角的坐标y;x1:矩形右下角的坐标x;y1:矩形右下角的坐标y | | set_overlap_zone | 设置指定图层的可视区域(矩形),可视区域会根据图层优先级,自动进行上下叠加。rect:可视矩形的位置信息;z_order:图层的z坐标(图层坐标) | | flush_screen | 将当前surface的指定矩形区域一次性刷在显示屏上。left:surface指定区域的左边界坐标;top:surface指定区域的上边界坐标;right:surface指定区域的右边界坐标;bottom:surface指定区域的下边界坐标 | | is_valid | 判断给定位置的矩形,是否合理(是否在surface的范围内)。rect:矩形区域的坐标信息 | *** | 函数名称 | wnd.cpp 函数接口注释 | | --- | --- | | c_wnd | c_wnd构造函数,进行基本初始化 | | connect | 把自己(this)、自己的子窗口系列及父窗口连接起来,形成完整的UI窗口链条;连接完成后,自己就可以响应用户输入及各种UI消息。parent:父窗口;resour_id:窗口ID;str:自己的窗口标题字符串;x:自己相对父窗口的坐标x;y:自己相对父窗口的坐标y;width:窗口宽度;height:窗口高度;p_child_tree:子窗口系列 | | load_child_wnd | 把一系列子窗口连接起来,形成完整的UI窗口链条;连接完成后,所有子窗口都可以响应用户输入及各种UI消息。p_child_tree:子窗口系列 | | disconnect | 把自己(this)跟父窗口、子窗口脱离连接,切断自己与UI的联系,不在响应用户输入及各种UI消息。 | | get_wnd_ptr | 获得指定窗口ID的窗口指针。id:窗口ID | | set_attr | 设置窗口属性,包括:普通、失效、可见。attr:属性值 | | is_focus_wnd | 判断自己(this)是否可以获得焦点 | | set_wnd_pos | 设置自己(this)相对于父窗口的窗口位置。x:窗口左上角坐标x;y:窗口左上角坐标y;width:窗口宽度;height:窗口高度 | | get_wnd_rect | 获取自己(this)相对于父窗口的位置信息。rect:用于输出位置信息 | | get_screen_rect | 获取自己(this)相对于UI系统的绝对位置信息。rect:用于输出位置信息 | | set_child_focus | 将自己(this)的一个子窗口设置为获得讲点状态。 focus_child:获得焦点的子窗口| | add_child_2_tail | 把一个子窗口添加到自己(this)的子窗口链表的尾部。child:被添加的子窗口 | | get_last_child | 获得自己(this)子窗口链表尾部的子窗口指针。 | | unlink_child | 将自己(this)的子窗口从子窗口链表中脱离出来。child:被脱链的子窗口 | | show_window | 渲染自己(this)及自己的子窗口 | | on_touch | 响应用户的触控消息。x:用户触控点的坐标x;y:用户触控点的坐标y;action:用户的触控类型,包括:按下,释放 | | on_key | 响应用户的按键消息。key:用户点击的按键键值。 | | notify_parent | 传递UI消息给自己(this)的父窗口,并调用父窗口对应的响应函数。msg_id:消息ID;ctrl_id:自己的资源ID,param:消息的参数 | ## 速成路线图 1. 精读源文件wnd.cpp中的connect, on_touch, on_key函数,理解界面元素的串联办法;理解响应触控操作的基本原理;理解响应硬按键的基本原理 2. 快速浏览surface.cpp中用于绘制的draw_xxx函数,熟悉基本的绘制接口;精读c_surface构造函数,理解c_surface类的各种成员关系 3. 精读button.cpp文件,初步掌握界面元素的基本开发方法 4. - 快速浏览HelloStar实例的BuildLinux/main.cpp,理解构建一般Linux应用的办法 - 快速浏览HelloStar实例的BuildMFC/HelloStarDlg.cpp,理解构建一般Windows应用的办法 - 快速浏览HelloStar实例的BuildSTM32F103-Keil/USER/main.c,理解构建一般单片机系统的办法 ================================================ FILE: documents/HowToWork.md ================================================ # How GuiLite work - [What GuiLite do?](#What-GuiLite-do-) - [How to customize/extend GuiLite?](#How-to-customize/extend-GuiLite-) - [Code intro](#Code-intro) - [Widgets management](#Widgets-management) - [Rendering](#Rendering) *** ## What GuiLite do? GuiLite do 2 things only: widgets management and rendering. Widgets management include: - Add/Remove GUI element(e.g, button, label, dialog), set caption and location. - Dispatch/Response intput message: By analysis the location information from the message, GuiLite would find the widget which should be reponse, and call response function(e.g, on_mouse_click, on_keyboard_click) - Dispatch/Response customer message: By analysis the ID of message, GuiLite would find response funciotn, and calll it(: on_timer, on_custmer_refresh) Rendering include: - Draw pixel, line, rect - Set frame layer; While your drawing, you should input frame layer index to make your drawing at a specific layer - Update frame layer; While frame layer changed(e.g, open/close dialog), GuiLite would determine which pixel of frame layer should be display on screen 👉Note: Rendering do not depend on Widgets management, In some case, you would render line/text/bitmap directly without any widgets in your GUI system. For example: Limted resource MCU platform. ## How to customize/extend GuiLite? In order to make GuiLite simple and clear, GuiLite only provide basic widgets(e.g, button, label, keyboard, spinx etc) implementation. If you want do more things on widgets, you can do it like this: - Update widgets code in GuiLite directly - Add new widgets file, and implement new widgets by reference GuiLite widgets code. If you would extend drawing method(e.g, draw circle/eclipse etc.), you can add your method in surface.cpp directly. How to render? See function draw_xxx() in surface.cpp word.cpp bitmap.cpp. ## Code intro core folder: - Implement message dispatch/response, multi frame layer management and rendering for all platforms - Adapter GuiLite on Windows/Linux/Android/iOS/macOS or none OS in adapter folder widgets folder: - Here are code for controllers(eg. button, lable, keyboard) and containers(eg. view, dialog, flip pages); You can redraw your own widget by modify this code. - Here are code for message transition(eg. finger press/release), it will pass finger press/release message to widget which been touched, and call callback function if defined. ## Widgets management Widgets include button, spinbox, label, keyboard, dialog, view; GuiLite will link all widgets by function: connect, then GuiLite will easy to find/add/remove any widget quickly. All the connections looks like a tree. For example: When you click a button, device get your finger location(x, y) will be send the root of the tree, GuiLite would find the button you click by comparing location information, then call the response function(e.g, repaint the button/change button status) ### How to create widgets? All widgets derived from class c_wnd. The widget will be created when the class has been instanced, at this time, the widget still alone, has nothing to do with UI system, could not response any user operation. ### How to link/unlink widgets By using "connect()" function, we can link this widget into widgets tree, then the widgets could response user touch/keyboard action. By using "disconnect()" function to unlink this widget from UI system. then the widget still live in memory, but could not response user touch/keyboard action any more. ## Rendering Rendering include rendering method and graphic management. - All rendering method base on draw_pixel() function - GuiLite support 3 frame layers so far, could handle 3 layers overlap senarios ### Rendering method - Basic rendering function: surface_cpp.cpp::draw_xxx() - Bitmap rendering function: bitmap.cpp::draw_bitmap_xxx() - For take GPU advantage, you can refactor draw_xxx() by using GPU feature ### Graphic layer ![Graphic layer](GraphicLayer.png)![GuiLiteGraphic](GuiLiteGraphic.gif) - display layer:This layer for physical display device, one UI has only one display layer - surface layer: One display layer have many surface layers, one surface layer represent one flip page - frame layer: One surface layer has many frame layers, one frame layer represent one layer in Z direction ## Source file annotation | core Importance/File name | Introduction | Time cost | | --- | --- | --- | | ★★★ wnd.h | Basic class for widgets; connect/disconnect widgets; response user on_touch, on_key action | 1.5 hour | | ★★ display.h | Initialize display device, create surface, | 0.5 hour | | word.h | Draw text | < 1 hour | | image.h | Draw bitmap | < 0.5 hour | | rect.h | Rect for basic use(e.g, widgets location) | < 0.5 hour | | api_linux.cpp | Adapter for Linux | < 0.5 hour | | api_win.cpp | Adapter for Windows | < 0.5 hour | | api_unknow.cpp | Adapter for other OS or none OS | < 0.5 hour | *** | widgets Difficulty/File name | Introduction | Time cost | | --- | --- | --- | | label.h | Draw label | < 0.5 hour | | button.h | Draw/Click button | < 0.5 hour | | table.h | Draw table | < 0.5 hour | | dialog.h | Draw/Open/Close dialog | < 0.5 hour | | ★ keyboard.h | Draw/Click keyboard | 0.5 hour | | ★★ list_box.h | Draw/Click list box | 1.5 hour | | ★★ spinbox.h | Draw/Click spin box | 1.5 hour | | ★★ edit.h | Draw/Click edit widget | 1.5 hour | | ★ slide_group.cpp | Draw multiple screens & Swip screen | 1.5 hour | | ★★★ wave_buffer.h | Manage wave buffer data | 1.5 hour | | ★★★ wave_ctrl.h | Draw wave widget with wave buffer data | 1.5 hour | ================================================ FILE: documents/UML.md ================================================ ## Class structure ![class-structure](uml-class.png) ## UI process ![ui-process](uml-ui-process.png) ================================================ FILE: src/.gitignore ================================================ # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Executables # *.exe *.out *.app # Visual studio Debug Release .vs # cmake CMakeCache.txt CMakeFiles cmake_install.cmake Makefile libGuiLite.a libGuiLite.so # Keil GuiLite.uvguix.* GuiLite.uvoptx Objects DebugConfig ================================================ FILE: src/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 2.8) PROJECT(GuiLite) SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}) ADD_DEFINITIONS(-DGUILITE_ON) # core FILE(GLOB CORE_SRC core/*.cpp) FILE(GLOB CORE_ADAPTER core/adapter/api_linux.cpp core/adapter/audio_linux.cpp) # widgets FILE(GLOB WIDGETS_SRC widgets/*.cpp) # build static library ADD_LIBRARY(GuiLite STATIC ${CORE_SRC} ${CORE_ADAPTER} ${WIDGETS_SRC}) # build shared library # ADD_LIBRARY(GuiLite SHARED ${CORE_SRC} ${CORE_ADAPTER} ${WIDGETS_SRC}) ================================================ FILE: src/GenerateGuiLite.h.sh ================================================ echo "Build header-only library: GuiLite.h" # build GuiLiteRaw.h cd core cat api.h resource.h theme.h display.h word.h image.h wnd.h > core.h mv core.h ../ cd .. cd widgets cat button.h dialog.h keyboard.h edit.h label.h list_box.h slide_group.h spinbox.h table.h wave_buffer.h wave_ctrl.h > widgets.h mv widgets.h ../ cd .. cat core.h widgets.h > GuiLiteRaw.h # build GuiLiteRaw.cpp cp core/core.cpp ./ cp widgets/widgets.cpp ./ cd core/adapter cat *.cpp > adapter.cpp mv adapter.cpp ../../ cd ../.. cat core.cpp adapter.cpp widgets.cpp > GuiLiteRaw.cpp # remove include core widgets from GuiLiteRaw.h sed -i '/^#include.*core\|widgets.*/d' GuiLiteRaw.h # remove all #pragma once sed -i '/^#pragma once/d' GuiLiteRaw.h # add #pragma once for 1st line sed -i '1 s/^/#pragma once\n/' GuiLiteRaw.h # remove include core widgets from GuiLiteRaw.cpp sed -i '/^#include.*core\|widgets.*/d' GuiLiteRaw.cpp # Delete empty lines or blank lines sed '/^$/d' GuiLiteRaw.h > GuiLite.h sed '/^$/d' GuiLiteRaw.cpp > GuiLite.cpp # Append GuiLite.cpp to GuiLite.h cat GuiLite.cpp >> GuiLite.h # Verify echo '#include "GuiLite.h"' > test.cpp gcc -c -D GUILITE_ON test.cpp mv GuiLite.h ../ echo "Done!" echo "You could find GuiLite.h in root folder" # clean rm *.h *.cpp *.o ================================================ FILE: src/GuiLite.sln ================================================ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28307.572 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GuiLite", "GuiLite.vcxproj", "{DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Debug|x64.ActiveCfg = Debug|x64 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Debug|x64.Build.0 = Debug|x64 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Debug|x86.ActiveCfg = Debug|Win32 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Debug|x86.Build.0 = Debug|Win32 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Release|x64.ActiveCfg = Release|x64 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Release|x64.Build.0 = Release|x64 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Release|x86.ActiveCfg = Release|Win32 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {50A71AAC-BDD2-499B-A992-6725DDB908AD} EndGlobalSection EndGlobal ================================================ FILE: src/GuiLite.uvprojx ================================================ 2.1
### uVision Project, (C) Keil Software
GuiLite 0x4 ARM-ADS 5060750::V5.06 update 6 (build 750)::ARMCC 0 STM32F103ZE STMicroelectronics Keil.STM32F1xx_DFP.2.3.0 http://www.keil.com/pack/ IRAM(0x20000000,0x00010000) IROM(0x08000000,0x00080000) CPUTYPE("Cortex-M3") CLOCK(12000000) ELITTLE UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_512 -FS08000000 -FL080000 -FP0($$Device:STM32F103ZE$Flash\STM32F10x_512.FLM)) 0 $$Device:STM32F103ZE$Device\Include\stm32f10x.h $$Device:STM32F103ZE$SVD\STM32F103xx.svd 0 0 0 0 0 0 1 .\Objects\ GuiLite 0 1 0 1 1 .\Listings\ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 3 1 SARMCM3.DLL -REMAP DCM.DLL -pCM3 SARMCM3.DLL TCM.DLL -pCM3 1 0 0 0 16 1 0 0 1 1 -1 1 BIN\UL2CM3.DLL 0 0 1 1 1 1 1 1 1 0 1 1 0 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 "Cortex-M3" 0 0 0 1 1 0 0 0 0 0 0 8 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0x0 0x0 0 0x0 0x0 0 0x0 0x0 0 0x0 0x0 0 0x0 0x0 0 0x0 0x0 0 0x20000000 0x10000 1 0x8000000 0x80000 0 0x0 0x0 1 0x0 0x0 1 0x0 0x0 1 0x0 0x0 1 0x8000000 0x80000 1 0x0 0x0 0 0x0 0x0 0 0x0 0x0 0 0x0 0x0 0 0x20000000 0x10000 0 0x0 0x0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 ./ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0x00000000 0x20000000 core api_unknow.cpp 8 .\core\adapter\api_unknow.cpp core.cpp 8 .\core\core.cpp widgets widgets.cpp 8 .\widgets\widgets.cpp
================================================ FILE: src/GuiLite.vcxproj ================================================  Debug Win32 Debug x64 MinSizeRel x64 Release Win32 MinSizeRel Win32 Release x64 RelWithDebInfo Win32 RelWithDebInfo x64 {DF7A4FAD-A68D-3E43-9C4B-7DE4EE77F732} 10.0 Win32Proj Win32 GuiLite NoUpgrade StaticLibrary Unicode v142 StaticLibrary Unicode v142 StaticLibrary Unicode v141 StaticLibrary Unicode v141 StaticLibrary MultiByte v141 StaticLibrary MultiByte v141 StaticLibrary MultiByte v141 StaticLibrary MultiByte v141 <_ProjectFileVersion>10.0.20506.1 $(SolutionDir)$(Configuration)\ $(Configuration)\ $(ProjectName) $(ProjectName) .lib .lib $(SolutionDir)$(Configuration)\ $(Configuration)\ $(ProjectName) $(ProjectName) .lib .lib $(SolutionDir)$(Configuration)\ $(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(SolutionDir);%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsCpp ProgramDatabase Sync Disabled Disabled NotUsing MultiThreadedDebugDLL true Level3 _CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir) WIN32;_DEBUG;_WINDOWS;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X86 $(SolutionDir);%(AdditionalIncludeDirectories) Debug/ EnableFastChecks CompileAsCpp ProgramDatabase Sync Disabled Disabled NotUsing MultiThreadedDebugDLL true Level3 GUILITE_ON;_CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir) WIN32;_DEBUG;_WINDOWS;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X64 $(SolutionDir);%(AdditionalIncludeDirectories) Release/ CompileAsCpp Sync AnySuitable MaxSpeed NotUsing MultiThreadedDLL true Level3 _CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X86 $(SolutionDir);%(AdditionalIncludeDirectories) Release/ CompileAsCpp Sync AnySuitable MaxSpeed NotUsing MultiThreadedDLL true Level3 _CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X64 %(AdditionalIncludeDirectories) MinSizeRel/ CompileAsCpp Sync OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR="MinSizeRel";%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR=\"MinSizeRel\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X86 %(AdditionalIncludeDirectories) MinSizeRel/ CompileAsCpp Sync OnlyExplicitInline MinSpace NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR="MinSizeRel";%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR=\"MinSizeRel\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X86 %(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsCpp ProgramDatabase Sync OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X86 %(AdditionalIncludeDirectories) RelWithDebInfo/ CompileAsCpp ProgramDatabase Sync OnlyExplicitInline MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) $(IntDir) WIN32;_WINDOWS;NDEBUG;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:X86 ================================================ FILE: src/GuiLite.vcxproj.filters ================================================  widgets core\adapter core {90BF9B29-451D-34AC-BF45-13C635ED39CD} {338d9696-2a1d-4569-b435-dd3da382a8d2} {691801eb-7076-4af6-aa0c-5ce5b0fcb21c} core core core core core core core widgets widgets widgets widgets widgets widgets widgets widgets widgets widgets widgets ================================================ FILE: src/core/adapter/api_linux.cpp ================================================ #ifdef GUILITE_ON #if ((defined __linux__) && (!defined __none_os__)) || (defined __APPLE__) #include "../../core/api.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_TIMER_CNT 10 #define TIMER_UNIT 50//ms static void(*do_assert)(const char* file, int line); static void(*do_log_out)(const char* log); void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) { do_assert = my_assert; do_log_out = my_log_out; } void _assert(const char* file, int line) { if(do_assert) { do_assert(file, line); } else { printf("assert@ file:%s, line:%d, error no: %d\n", file, line, errno); } } void log_out(const char* log) { if (do_log_out) { do_log_out(log); } else { printf("%s", log); fflush(stdout); } } typedef struct _timer_manage { struct _timer_info { int state; /* on or off */ int interval; int elapse; /* 0~interval */ void (* timer_proc) (void* param); void* param; }timer_info[MAX_TIMER_CNT]; void (* old_sigfunc)(int); void (* new_sigfunc)(int); }_timer_manage_t; static struct _timer_manage timer_manage; static void* timer_routine(void*) { int i; while(true) { for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 0) { continue; } timer_manage.timer_info[i].elapse++; if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) { timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); } } usleep(1000 * TIMER_UNIT); } return NULL; } static int init_mul_timer() { static bool s_is_init = false; if(s_is_init == true) { return 0; } memset(&timer_manage, 0, sizeof(struct _timer_manage)); pthread_t pid; pthread_create(&pid, NULL, timer_routine, NULL); s_is_init = true; return 1; } static int set_a_timer(int interval, void (* timer_proc)(void* param), void* param) { init_mul_timer(); int i; if(timer_proc == NULL || interval <= 0) { return (-1); } for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 1) { continue; } memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); timer_manage.timer_info[i].timer_proc = timer_proc; timer_manage.timer_info[i].param = param; timer_manage.timer_info[i].interval = interval; timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].state = 1; break; } if(i >= MAX_TIMER_CNT) { ASSERT(false); return (-1); } return (i); } typedef void (*EXPIRE_ROUTINE)(void* arg); EXPIRE_ROUTINE s_expire_function; static c_fifo s_real_timer_fifo; static void* real_timer_routine(void*) { char dummy; while(1) { if(s_real_timer_fifo.read(&dummy, 1) > 0) { if(s_expire_function)s_expire_function(0); } else { ASSERT(false); } } return 0; } static void expire_real_timer(int sigo) { char dummy = 0x33; if(s_real_timer_fifo.write(&dummy, 1) <= 0) { ASSERT(false); } } void start_real_timer(void (*func)(void* arg)) { if(NULL == func) { return; } s_expire_function = func; signal(SIGALRM, expire_real_timer); struct itimerval value, ovalue; value.it_value.tv_sec = 0; value.it_value.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; value.it_interval.tv_sec = 0; value.it_interval.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; setitimer(ITIMER_REAL, &value, &ovalue); static pthread_t s_pid; if(s_pid == 0) { pthread_create(&s_pid, NULL, real_timer_routine, NULL); } } unsigned int get_cur_thread_id() { return (unsigned long)pthread_self(); } void register_timer(int milli_second,void func(void* param), void* param) { set_a_timer(milli_second/TIMER_UNIT,func, param); } long get_time_in_second() { return time(NULL); /* + 8*60*60*/ } T_TIME get_time() { T_TIME ret = {0}; struct tm *fmt; time_t timer; timer = get_time_in_second(); fmt = localtime(&timer); ret.year = fmt->tm_year + 1900; ret.month = fmt->tm_mon + 1; ret.day = fmt->tm_mday; ret.hour = fmt->tm_hour; ret.minute = fmt->tm_min; ret.second = fmt->tm_sec; return ret; } T_TIME second_to_day(long second) { T_TIME ret = {0}; struct tm *fmt; fmt = localtime(&second); ret.year = fmt->tm_year + 1900; ret.month = fmt->tm_mon + 1; ret.day = fmt->tm_mday; ret.hour = fmt->tm_hour; ret.minute = fmt->tm_min; ret.second = fmt->tm_sec; return ret; } void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) { pthread_create((pthread_t*)thread_id, (pthread_attr_t const*)attr, start_routine, arg); } void thread_sleep(unsigned int milli_seconds) { usleep(milli_seconds * 1000); } typedef struct { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; }__attribute__((packed))FileHead; typedef struct{ unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompress; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; unsigned int biRedMask; unsigned int biGreenMask; unsigned int biBlueMask; }__attribute__((packed))Infohead; int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) { FileHead bmp_head; Infohead bmp_info; int size = width * height * 2; //initialize bmp head. bmp_head.bfType = 0x4d42; bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; bmp_head.bfOffBits = bmp_head.bfSize - size; //initialize bmp info. bmp_info.biSize = 40; bmp_info.biWidth = width; bmp_info.biHeight = height; bmp_info.biPlanes = 1; bmp_info.biBitCount = 16; bmp_info.biCompress = 3; bmp_info.biSizeImage = size; bmp_info.biXPelsPerMeter = 0; bmp_info.biYPelsPerMeter = 0; bmp_info.biClrUsed = 0; bmp_info.biClrImportant = 0; //RGB565 bmp_info.biRedMask = 0xF800; bmp_info.biGreenMask = 0x07E0; bmp_info.biBlueMask = 0x001F; //copy the data FILE *fp; if(!(fp=fopen(filename,"wb"))) { return -1; } fwrite(&bmp_head, 1, sizeof(FileHead),fp); fwrite(&bmp_info, 1, sizeof(Infohead),fp); //fwrite(data, 1, size, fp);//top <-> bottom for (int i = (height - 1); i >= 0; --i) { fwrite(&data[i * width * 2], 1, width * 2, fp); } fclose(fp); return 0; } c_fifo::c_fifo() { m_head = m_tail = 0; m_read_sem = malloc(sizeof(sem_t)); m_write_mutex = malloc(sizeof(pthread_mutex_t)); sem_init((sem_t*)m_read_sem, 0, 0); pthread_mutex_init((pthread_mutex_t*)m_write_mutex, 0); } int c_fifo::read(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; while(i < len) { if (m_tail == m_head) {//empty sem_wait((sem_t*)m_read_sem); continue; } *pbuf++ = m_buf[m_head]; m_head = (m_head + 1) % FIFO_BUFFER_LEN; i++; } if(i != len) { ASSERT(false); } return i; } int c_fifo::write(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; int tail = m_tail; pthread_mutex_lock((pthread_mutex_t*)m_write_mutex); while(i < len) { if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) {//full, clear data has been written; m_tail = tail; log_out("Warning: fifo full\n"); pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); return 0; } m_buf[m_tail] = *pbuf++; m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; i++; } pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); if(i != len) { ASSERT(false); } else { sem_post((sem_t*)m_read_sem); } return i; } #endif #endif ================================================ FILE: src/core/adapter/api_unknow.cpp ================================================ #ifdef GUILITE_ON #if (defined __none_os__) || ((!defined _WIN32) && (!defined WIN32) && (!defined _WIN64) && (!defined WIN64) && (!defined __linux__) && (!defined __APPLE__)) #include "../../core/api.h" #include static void(*do_assert)(const char* file, int line); static void(*do_log_out)(const char* log); void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) { do_assert = my_assert; do_log_out = my_log_out; } void _assert(const char* file, int line) { if(do_assert) { do_assert(file, line); } while(1); } void log_out(const char* log) { if (do_log_out) { do_log_out(log); } } long get_time_in_second() { return 0; } T_TIME second_to_day(long second) { T_TIME ret = {0}; return ret; } T_TIME get_time() { T_TIME ret = {0}; return ret; } void start_real_timer(void (*func)(void* arg)) { log_out("Not support now"); } void register_timer(int milli_second, void func(void* ptmr, void* parg)) { log_out("Not support now"); } unsigned int get_cur_thread_id() { log_out("Not support now"); return 0; } void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) { log_out("Not support now"); } extern "C" void delay_ms(unsigned short nms); void thread_sleep(unsigned int milli_seconds) {//MCU alway implemnet driver code in APP. delay_ms(milli_seconds); } int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) { log_out("Not support now"); return 0; } c_fifo::c_fifo() { m_head = m_tail = 0; m_read_sem = m_write_mutex = 0; } int c_fifo::read(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; while(i < len) { if (m_tail == m_head) {//empty continue; } *pbuf++ = m_buf[m_head]; m_head = (m_head + 1) % FIFO_BUFFER_LEN; i++; } if(i != len) { ASSERT(false); } return i; } int c_fifo::write(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; int tail = m_tail; while(i < len) { if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) {//full, clear data has been written; m_tail = tail; log_out("Warning: fifo full\n"); return 0; } m_buf[m_tail] = *pbuf++; m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; i++; } if(i != len) { ASSERT(false); } return i; } #endif #endif ================================================ FILE: src/core/adapter/api_win.cpp ================================================ #ifdef GUILITE_ON #if (defined _WIN32) || (defined WIN32) || (defined _WIN64) || (defined WIN64) #include "../../core/api.h" #include #include #include #include #include #include #define MAX_TIMER_CNT 10 #define TIMER_UNIT 50//ms static void(*do_assert)(const char* file, int line); static void(*do_log_out)(const char* log); void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) { do_assert = my_assert; do_log_out = my_log_out; } void _assert(const char* file, int line) { static char s_buf[192]; if (do_assert) { do_assert(file, line); } else { memset(s_buf, 0, sizeof(s_buf)); sprintf_s(s_buf, sizeof(s_buf), "vvvvvvvvvvvvvvvvvvvvvvvvvvvv\n\nAssert@ file = %s, line = %d\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", file, line); OutputDebugStringA(s_buf); printf("%s", s_buf); fflush(stdout); assert(false); } } void log_out(const char* log) { if (do_log_out) { do_log_out(log); } else { printf("%s", log); fflush(stdout); OutputDebugStringA(log); } } typedef struct _timer_manage { struct _timer_info { int state; /* on or off */ int interval; int elapse; /* 0~interval */ void (* timer_proc) (void* param); void* param; }timer_info[MAX_TIMER_CNT]; void (* old_sigfunc)(int); void (* new_sigfunc)(int); }_timer_manage_t; static struct _timer_manage timer_manage; DWORD WINAPI timer_routine(LPVOID lpParam) { int i; while(true) { for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 0) { continue; } timer_manage.timer_info[i].elapse++; if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) { timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); } } Sleep(TIMER_UNIT); } return 0; } static int init_mul_timer() { static bool s_is_init = false; if(s_is_init == true) { return 0; } memset(&timer_manage, 0, sizeof(struct _timer_manage)); DWORD pid; CreateThread(0, 0, timer_routine, 0, 0, &pid); s_is_init = true; return 1; } static int set_a_timer(int interval, void (* timer_proc) (void* param), void* param) { init_mul_timer(); int i; if(timer_proc == 0 || interval <= 0) { return (-1); } for(i = 0; i < MAX_TIMER_CNT; i++) { if(timer_manage.timer_info[i].state == 1) { continue; } memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); timer_manage.timer_info[i].timer_proc = timer_proc; timer_manage.timer_info[i].param = param; timer_manage.timer_info[i].interval = interval; timer_manage.timer_info[i].elapse = 0; timer_manage.timer_info[i].state = 1; break; } if(i >= MAX_TIMER_CNT) { ASSERT(false); return (-1); } return (i); } typedef void (*EXPIRE_ROUTINE)(void* arg); EXPIRE_ROUTINE s_expire_function; static c_fifo s_real_timer_fifo; static DWORD WINAPI fire_real_timer(LPVOID lpParam) { char dummy; while(1) { if(s_real_timer_fifo.read(&dummy, 1) > 0) { if(s_expire_function)s_expire_function(0); } else { ASSERT(false); } } return 0; } /*Win32 desktop only static void CALLBACK trigger_real_timer(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR) { char dummy = 0x33; s_real_timer_fifo.write(&dummy, 1); } */ static DWORD WINAPI trigger_real_timer(LPVOID lpParam) { char dummy = 0x33; while (1) { s_real_timer_fifo.write(&dummy, 1); Sleep(REAL_TIME_TASK_CYCLE_MS); } return 0; } void start_real_timer(void (*func)(void* arg)) { if(0 == func) { return; } s_expire_function = func; //timeSetEvent(REAL_TIME_TASK_CYCLE_MS, 0, trigger_real_timer, 0, TIME_PERIODIC);//Win32 desktop only static DWORD s_pid; if(s_pid == 0) { CreateThread(0, 0, trigger_real_timer, 0, 0, &s_pid); CreateThread(0, 0, fire_real_timer, 0, 0, &s_pid); } } unsigned int get_cur_thread_id() { return GetCurrentThreadId(); } void register_timer(int milli_second,void func(void* param), void* param) { set_a_timer(milli_second/TIMER_UNIT,func, param); } long get_time_in_second() { return (long)time(0); } T_TIME get_time() { T_TIME ret = {0}; SYSTEMTIME time; GetLocalTime(&time); ret.year = time.wYear; ret.month = time.wMonth; ret.day = time.wDay; ret.hour = time.wHour; ret.minute = time.wMinute; ret.second = time.wSecond; return ret; } T_TIME second_to_day(long second) { T_TIME ret; ret.year = 1999; ret.month = 10; ret.date = 1; ret.second = second % 60; second /= 60; ret.minute = second % 60; second /= 60; ret.hour = (second + 8) % 24;//China time zone. return ret; } void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) { DWORD pid = 0; CreateThread(0, 0, LPTHREAD_START_ROUTINE(start_routine), arg, 0, &pid); *thread_id = pid; } void thread_sleep(unsigned int milli_seconds) { Sleep(milli_seconds); } #pragma pack(push,1) typedef struct { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; }FileHead; typedef struct { unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompress; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; unsigned int biRedMask; unsigned int biGreenMask; unsigned int biBlueMask; }Infohead; #pragma pack(pop) int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) { FileHead bmp_head; Infohead bmp_info; int size = width * height * 2; //initialize bmp head. bmp_head.bfType = 0x4d42; bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; bmp_head.bfOffBits = bmp_head.bfSize - size; //initialize bmp info. bmp_info.biSize = 40; bmp_info.biWidth = width; bmp_info.biHeight = height; bmp_info.biPlanes = 1; bmp_info.biBitCount = 16; bmp_info.biCompress = 3; bmp_info.biSizeImage = size; bmp_info.biXPelsPerMeter = 0; bmp_info.biYPelsPerMeter = 0; bmp_info.biClrUsed = 0; bmp_info.biClrImportant = 0; //RGB565 bmp_info.biRedMask = 0xF800; bmp_info.biGreenMask = 0x07E0; bmp_info.biBlueMask = 0x001F; //copy the data FILE *fp; if (!(fp = fopen(filename, "wb"))) { return -1; } fwrite(&bmp_head, 1, sizeof(FileHead), fp); fwrite(&bmp_info, 1, sizeof(Infohead), fp); //fwrite(data, 1, size, fp);//top <-> bottom for (int i = (height - 1); i >= 0; --i) { fwrite(&data[i * width * 2], 1, width * 2, fp); } fclose(fp); return 0; } c_fifo::c_fifo() { m_head = m_tail = 0; m_read_sem = CreateSemaphore(0, // default security attributes 0, // initial count 1, // maximum count 0); // unnamed semaphore m_write_mutex = CreateMutex(0, false, 0); } int c_fifo::read(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; while (i < len) { if (m_tail == m_head) {//empty WaitForSingleObject(m_read_sem, INFINITE); continue; } *pbuf++ = m_buf[m_head]; m_head = (m_head + 1) % FIFO_BUFFER_LEN; i++; } if (i != len) { ASSERT(false); } return i; } int c_fifo::write(void* buf, int len) { unsigned char* pbuf = (unsigned char*)buf; int i = 0; int tail = m_tail; WaitForSingleObject(m_write_mutex, INFINITE); while (i < len) { if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) {//full, clear data has been written; m_tail = tail; log_out("Warning: fifo full\n"); ReleaseMutex(m_write_mutex); return 0; } m_buf[m_tail] = *pbuf++; m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; i++; } ReleaseMutex(m_write_mutex); if (i != len) { ASSERT(false); } else { ReleaseSemaphore(m_read_sem, 1, 0); } return i; } #endif #endif ================================================ FILE: src/core/api.h ================================================ #pragma once #define REAL_TIME_TASK_CYCLE_MS 50 #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) #define GL_ARGB(a, r, g, b) ((((unsigned int)(a)) << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) #define GL_ARGB_A(rgb) ((((unsigned int)(rgb)) >> 24) & 0xFF) #define GL_RGB(r, g, b) ((0xFF << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) #define GL_RGB_R(rgb) ((((unsigned int)(rgb)) >> 16) & 0xFF) #define GL_RGB_G(rgb) ((((unsigned int)(rgb)) >> 8) & 0xFF) #define GL_RGB_B(rgb) (((unsigned int)(rgb)) & 0xFF) #define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8)) #define GL_RGB_16_to_32(rgb) ((0xFF << 24) | ((((unsigned int)(rgb)) & 0x1F) << 3) | ((((unsigned int)(rgb)) & 0x7E0) << 5) | ((((unsigned int)(rgb)) & 0xF800) << 8)) #define ALIGN_HCENTER 0x00000000L #define ALIGN_LEFT 0x01000000L #define ALIGN_RIGHT 0x02000000L #define ALIGN_HMASK 0x03000000L #define ALIGN_VCENTER 0x00000000L #define ALIGN_TOP 0x00100000L #define ALIGN_BOTTOM 0x00200000L #define ALIGN_VMASK 0x00300000L typedef struct { unsigned short year; unsigned short month; unsigned short date; unsigned short day; unsigned short hour; unsigned short minute; unsigned short second; }T_TIME; void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)); void _assert(const char* file, int line); #define ASSERT(condition) \ do{ \ if(!(condition))_assert(__FILE__, __LINE__);\ }while(0) void log_out(const char* log); long get_time_in_second(); T_TIME second_to_day(long second); T_TIME get_time(); void start_real_timer(void (*func)(void* arg)); void register_timer(int milli_second, void func(void* param), void* param); unsigned int get_cur_thread_id(); void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg); void thread_sleep(unsigned int milli_seconds); int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data); #define FIFO_BUFFER_LEN 1024 class c_fifo { public: c_fifo(); int read(void* buf, int len); int write(void* buf, int len); private: unsigned char m_buf[FIFO_BUFFER_LEN]; int m_head; int m_tail; void* m_read_sem; void* m_write_mutex; }; class c_rect { public: c_rect(){ m_left = m_top = m_right = m_bottom = -1; }//empty rect c_rect(int left, int top, int width, int height) { set_rect(left, top, width, height); } void set_rect(int left, int top, int width, int height) { ASSERT(width > 0 && height > 0); m_left = left; m_top = top; m_right = left + width - 1; m_bottom = top + height -1; } bool pt_in_rect(int x, int y) const { return x >= m_left && x <= m_right && y >= m_top && y <= m_bottom; } int operator==(const c_rect& rect) const { return (m_left == rect.m_left) && (m_top == rect.m_top) && (m_right == rect.m_right) && (m_bottom == rect.m_bottom); } int width() const { return m_right - m_left + 1; } int height() const { return m_bottom - m_top + 1 ; } int m_left; int m_top; int m_right; int m_bottom; }; ================================================ FILE: src/core/core.cpp ================================================ #include "../core/display.h" #include "../core//image.h" #include "../core/theme.h" #include "../core/wnd.h" #include "../core/word.h" #ifdef GUILITE_ON c_bitmap_operator the_bitmap_op = c_bitmap_operator(); c_image_operator* c_image::image_operator = &the_bitmap_op; const void* c_theme::s_font_map[FONT_MAX]; const void* c_theme::s_image_map[IMAGE_MAX]; unsigned int c_theme::s_color_map[COLOR_MAX]; c_lattice_font_op the_lattice_font_op = c_lattice_font_op(); c_font_operator* c_word::fontOperator = &the_lattice_font_op; #endif ================================================ FILE: src/core/display.h ================================================ #pragma once #include "../core/api.h" #include #include #include #define SURFACE_CNT_MAX 6//root + pages typedef enum { Z_ORDER_LEVEL_0,//lowest graphic level Z_ORDER_LEVEL_1,//middle graphic level, call activate_layer before use it, draw everything inside the active rect. Z_ORDER_LEVEL_2,//highest graphic level, call activate_layer before use it, draw everything inside the active rect. Z_ORDER_LEVEL_MAX }Z_ORDER_LEVEL; struct DISPLAY_DRIVER { void(*draw_pixel)(int x, int y, unsigned int rgb); void(*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb); }; class c_surface; class c_display { friend class c_surface; public: inline c_display(void* phy_fb, int display_width, int display_height, c_surface* surface, DISPLAY_DRIVER* driver = 0);//single custom surface inline c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, DISPLAY_DRIVER* driver = 0);//multiple surface inline c_surface* alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect = c_rect());//for slide group inline int swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset); int get_width() { return m_width; } int get_height() { return m_height; } void* get_phy_fb() { return m_phy_fb; } void* get_updated_fb(int* width, int* height, bool force_update = false) { if (width && height) { *width = m_width; *height = m_height; } if (force_update) { return m_phy_fb; } if (m_phy_read_index == m_phy_write_index) {//No update return 0; } m_phy_read_index = m_phy_write_index; return m_phy_fb; } int snap_shot(const char* file_name) { if (!m_phy_fb || (m_color_bytes !=2 && m_color_bytes != 4)) { return -1; } //16 bits framebuffer if (m_color_bytes == 2) { return build_bmp(file_name, m_width, m_height, (unsigned char*)m_phy_fb); } //32 bits framebuffer unsigned short* p_bmp565_data = new unsigned short[m_width * m_height]; unsigned int* p_raw_data = (unsigned int*)m_phy_fb; for (int i = 0; i < m_width * m_height; i++) { unsigned int rgb = *p_raw_data++; p_bmp565_data[i] = GL_RGB_32_to_16(rgb); } int ret = build_bmp(file_name, m_width, m_height, (unsigned char*)p_bmp565_data); delete[]p_bmp565_data; return ret; } protected: virtual void draw_pixel(int x, int y, unsigned int rgb) { if ((x >= m_width) || (y >= m_height)) { return; } if (m_driver && m_driver->draw_pixel) { return m_driver->draw_pixel(x, y, rgb); } if (m_color_bytes == 2) { ((unsigned short*)m_phy_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb); } else { ((unsigned int*)m_phy_fb)[y * m_width + x] = rgb; } } virtual void fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) { if (m_driver && m_driver->fill_rect) { return m_driver->fill_rect(x0, y0, x1, y1, rgb); } if (m_driver && m_driver->draw_pixel) { for (int y = y0; y <= y1; y++) { for (int x = x0; x <= x1; x++) { m_driver->draw_pixel(x, y, rgb); } } return; } int _width = m_width; int _height = m_height; int x, y; if (m_color_bytes == 2) { unsigned short* phy_fb; unsigned int rgb_16 = GL_RGB_32_to_16(rgb); for (y = y0; y <= y1; y++) { phy_fb = &((unsigned short*)m_phy_fb)[y * _width + x0]; for (x = x0; x <= x1; x++) { if ((x < _width) && (y < _height)) { *phy_fb++ = rgb_16; } } } } else { unsigned int* phy_fb; for (y = y0; y <= y1; y++) { phy_fb = &((unsigned int*)m_phy_fb)[y * _width + x0]; for (x = x0; x <= x1; x++) { if ((x < _width) && (y < _height)) { *phy_fb++ = rgb; } } } } } virtual int flush_screen(int left, int top, int right, int bottom, void* fb, int fb_width) { if ((0 == m_phy_fb) || (0 == fb)) { return -1; } int _width = m_width; int _height = m_height; left = (left >= _width) ? (_width - 1) : left; right = (right >= _width) ? (_width - 1) : right; top = (top >= _height) ? (_height - 1) : top; bottom = (bottom >= _height) ? (_height - 1) : bottom; for (int y = top; y < bottom; y++) { void* s_addr = (char*)fb + ((y * fb_width + left) * m_color_bytes); void* d_addr = (char*)m_phy_fb + ((y * _width + left) * m_color_bytes); memcpy(d_addr, s_addr, (right - left) * m_color_bytes); } return 0; } int m_width; //in pixels int m_height; //in pixels int m_color_bytes; //16/32 bits for default void* m_phy_fb; //physical framebuffer for default struct DISPLAY_DRIVER* m_driver; //Rendering by external method without default physical framebuffer int m_phy_read_index; int m_phy_write_index; c_surface* m_surface_group[SURFACE_CNT_MAX]; int m_surface_cnt; //surface count int m_surface_index; }; class c_layer { public: c_layer() { fb = 0; } void* fb; //framebuffer c_rect rect; //framebuffer area c_rect active_rect; }; class c_surface { friend class c_display; friend class c_bitmap_operator; public: Z_ORDER_LEVEL get_max_z_order() { return m_max_zorder; } c_surface(unsigned int width, unsigned int height, unsigned int color_bytes, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0, c_rect overlpa_rect = c_rect()) : m_width(width), m_height(height), m_color_bytes(color_bytes), m_fb(0), m_is_active(false), m_top_zorder(Z_ORDER_LEVEL_0), m_phy_write_index(0), m_display(0) { (overlpa_rect == c_rect()) ? set_surface(max_zorder, c_rect(0, 0, width, height)) : set_surface(max_zorder, overlpa_rect); } unsigned int get_pixel(int x, int y, unsigned int z_order) { if (x >= m_width || y >= m_height || x < 0 || y < 0 || z_order >= Z_ORDER_LEVEL_MAX) { ASSERT(false); return 0; } if (m_layers[z_order].fb) { return (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)(m_layers[z_order].fb))[y * m_width + x]) : ((unsigned int*)(m_layers[z_order].fb))[y * m_width + x]; } else if (m_fb) { return (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)m_fb)[y * m_width + x]) : ((unsigned int*)m_fb)[y * m_width + x]; } else if (m_display->m_phy_fb) { return (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)m_display->m_phy_fb)[y * m_width + x]) : ((unsigned int*)m_display->m_phy_fb)[y * m_width + x]; } return 0; } virtual void draw_pixel(int x, int y, unsigned int rgb, unsigned int z_order) { if (x >= m_width || y >= m_height || x < 0 || y < 0) { return; } if (z_order > (unsigned int)m_max_zorder) { ASSERT(false); return; } if (z_order > (unsigned int)m_top_zorder) { m_top_zorder = (Z_ORDER_LEVEL)z_order; } if (z_order == m_max_zorder) { return draw_pixel_low_level(x, y, rgb); } if (m_layers[z_order].rect.pt_in_rect(x, y)) { c_rect layer_rect = m_layers[z_order].rect; if (m_color_bytes == 2) { ((unsigned short*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = GL_RGB_32_to_16(rgb); } else { ((unsigned int*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = rgb; } } if (z_order == m_top_zorder) { return draw_pixel_low_level(x, y, rgb); } bool be_overlapped = false; for (unsigned int tmp_z_order = Z_ORDER_LEVEL_MAX - 1; tmp_z_order > z_order; tmp_z_order--) { if (m_layers[tmp_z_order].active_rect.pt_in_rect(x, y)) { be_overlapped = true; break; } } if (!be_overlapped) { draw_pixel_low_level(x, y, rgb); } } virtual void fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order) { x0 = (x0 < 0) ? 0 : x0; y0 = (y0 < 0) ? 0 : y0; x1 = (x1 > (m_width - 1)) ? (m_width - 1) : x1; y1 = (y1 > (m_height - 1)) ? (m_height - 1) : y1; if (z_order == m_max_zorder) { return fill_rect_low_level(x0, y0, x1, y1, rgb); } if (z_order == m_top_zorder) { int width = m_layers[z_order].rect.width(); c_rect layer_rect = m_layers[z_order].rect; unsigned int rgb_16 = GL_RGB_32_to_16(rgb); for (int y = y0; y <= y1; y++) { for (int x = x0; x <= x1; x++) { if (layer_rect.pt_in_rect(x, y)) { if (m_color_bytes == 2) { ((unsigned short*)m_layers[z_order].fb)[(y - layer_rect.m_top) * width + (x - layer_rect.m_left)] = rgb_16; } else { ((unsigned int*)m_layers[z_order].fb)[(y - layer_rect.m_top) * width + (x - layer_rect.m_left)] = rgb; } } } } return fill_rect_low_level(x0, y0, x1, y1, rgb); } for (; y0 <= y1; y0++) { draw_hline(x0, x1, y0, rgb, z_order); } } void draw_hline(int x0, int x1, int y, unsigned int rgb, unsigned int z_order) { for (; x0 <= x1; x0++) { draw_pixel(x0, y, rgb, z_order); } } void draw_vline(int x, int y0, int y1, unsigned int rgb, unsigned int z_order) { for (; y0 <= y1; y0++) { draw_pixel(x, y0, rgb, z_order); } } void draw_line(int x1, int y1, int x2, int y2, unsigned int rgb, unsigned int z_order) { int dx, dy, x, y, e; (x1 > x2) ? (dx = x1 - x2) : (dx = x2 - x1); (y1 > y2) ? (dy = y1 - y2) : (dy = y2 - y1); if (((dx > dy) && (x1 > x2)) || ((dx <= dy) && (y1 > y2))) { x = x2; y = y2; x2 = x1; y2 = y1; x1 = x; y1 = y; } x = x1; y = y1; if (dx > dy) { e = dy - dx / 2; for (; x1 <= x2; ++x1, e += dy) { draw_pixel(x1, y1, rgb, z_order); if (e > 0) { e -= dx; (y > y2) ? --y1 : ++y1; } } } else { e = dx - dy / 2; for (; y1 <= y2; ++y1, e += dx) { draw_pixel(x1, y1, rgb, z_order); if (e > 0) { e -= dy; (x > x2) ? --x1 : ++x1; } } } } void draw_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order, unsigned int size = 1) { for (unsigned int offset = 0; offset < size; offset++) { draw_hline(x0 + offset, x1 - offset, y0 + offset, rgb, z_order); draw_hline(x0 + offset, x1 - offset, y1 - offset, rgb, z_order); draw_vline(x0 + offset, y0 + offset, y1 - offset, rgb, z_order); draw_vline(x1 - offset, y0 + offset, y1 - offset, rgb, z_order); } } void draw_rect(c_rect rect, unsigned int rgb, unsigned int size, unsigned int z_order) { draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order, size); } void fill_rect(c_rect rect, unsigned int rgb, unsigned int z_order) { fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order); } int flush_screen(int left, int top, int right, int bottom) { if (!m_is_active) { return -1; } if (left < 0 || left >= m_width || right < 0 || right >= m_width || top < 0 || top >= m_height || bottom < 0 || bottom >= m_height) { ASSERT(false); } m_display->flush_screen(left, top, right, bottom, m_fb, m_width); *m_phy_write_index = *m_phy_write_index + 1; return 0; } bool is_active() { return m_is_active; } c_display* get_display() { return m_display; } void activate_layer(c_rect active_rect, unsigned int active_z_order)//empty active rect means inactivating the layer { ASSERT(active_z_order > Z_ORDER_LEVEL_0 && active_z_order <= Z_ORDER_LEVEL_MAX); //Show the layers below the current active rect. c_rect current_active_rect = m_layers[active_z_order].active_rect; for(int low_z_order = Z_ORDER_LEVEL_0; low_z_order < active_z_order; low_z_order++) { c_rect low_layer_rect = m_layers[low_z_order].rect; c_rect low_active_rect = m_layers[low_z_order].active_rect; void* fb = m_layers[low_z_order].fb; int width = low_layer_rect.width(); for (int y = current_active_rect.m_top; y <= current_active_rect.m_bottom; y++) { for (int x = current_active_rect.m_left; x <= current_active_rect.m_right; x++) { if (low_active_rect.pt_in_rect(x, y) && low_layer_rect.pt_in_rect(x, y))//active rect maybe is bigger than layer rect { unsigned int rgb = (m_color_bytes == 2) ? GL_RGB_16_to_32(((unsigned short*)fb)[(x - low_layer_rect.m_left) + (y - low_layer_rect.m_top) * width]) : ((unsigned int*)fb)[(x - low_layer_rect.m_left) + (y - low_layer_rect.m_top) * width]; draw_pixel_low_level(x, y, rgb); } } } } m_layers[active_z_order].active_rect = active_rect;//set the new acitve rect. } void set_active(bool flag) { m_is_active = flag; } protected: virtual void fill_rect_low_level(int x0, int y0, int x1, int y1, unsigned int rgb) {//fill rect on framebuffer of surface int x, y; if (m_color_bytes == 2) { unsigned short* fb; unsigned int rgb_16 = GL_RGB_32_to_16(rgb); for (y = y0; y <= y1; y++) { fb = m_fb ? &((unsigned short*)m_fb)[y * m_width + x0] : 0; if (!fb) { break; } for (x = x0; x <= x1; x++) { *fb++ = rgb_16; } } } else { unsigned int* fb; for (y = y0; y <= y1; y++) { fb = m_fb ? &((unsigned int*)m_fb)[y * m_width + x0] : 0; if (!fb) { break; } for (x = x0; x <= x1; x++) { *fb++ = rgb; } } } if (!m_is_active) { return; } m_display->fill_rect(x0, y0, x1, y1, rgb); *m_phy_write_index = *m_phy_write_index + 1; } virtual void draw_pixel_low_level(int x, int y, unsigned int rgb) { if (m_fb) {//draw pixel on framebuffer of surface (m_color_bytes == 2) ? ((unsigned short*)m_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb): ((unsigned int*)m_fb)[y * m_width + x] = rgb; } if (!m_is_active) { return; } m_display->draw_pixel(x, y, rgb); *m_phy_write_index = *m_phy_write_index + 1; } void attach_display(c_display* display) { ASSERT(display); m_display = display; m_phy_write_index = &display->m_phy_write_index; } void set_surface(Z_ORDER_LEVEL max_z_order, c_rect layer_rect) { m_max_zorder = max_z_order; if (m_display && (m_display->m_surface_cnt > 1)) { m_fb = calloc(m_width * m_height, m_color_bytes); } for (int i = Z_ORDER_LEVEL_0; i < m_max_zorder; i++) {//Top layber fb always be 0 ASSERT(m_layers[i].fb = calloc(layer_rect.width() * layer_rect.height(), m_color_bytes)); m_layers[i].rect = layer_rect; } m_layers[Z_ORDER_LEVEL_0].active_rect = layer_rect; } int m_width; //in pixels int m_height; //in pixels int m_color_bytes; //16 bits, 32 bits for default void* m_fb; //frame buffer you could see c_layer m_layers[Z_ORDER_LEVEL_MAX];//all graphic layers bool m_is_active; //active flag Z_ORDER_LEVEL m_max_zorder; //the highest graphic layer the surface will have Z_ORDER_LEVEL m_top_zorder; //the current highest graphic layer the surface have int* m_phy_write_index; c_display* m_display; }; inline c_display::c_display(void* phy_fb, int display_width, int display_height, c_surface* surface, DISPLAY_DRIVER* driver) : m_phy_fb(phy_fb), m_width(display_width), m_height(display_height), m_driver(driver), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(1), m_surface_index(0) { m_color_bytes = surface->m_color_bytes; surface->m_is_active = true; (m_surface_group[0] = surface)->attach_display(this); } inline c_display::c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, DISPLAY_DRIVER* driver) : m_phy_fb(phy_fb), m_width(display_width), m_height(display_height), m_color_bytes(color_bytes), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(surface_cnt), m_driver(driver), m_surface_index(0) { ASSERT(color_bytes == 2 || color_bytes == 4); ASSERT(m_surface_cnt <= SURFACE_CNT_MAX); memset(m_surface_group, 0, sizeof(m_surface_group)); for (int i = 0; i < m_surface_cnt; i++) { m_surface_group[i] = new c_surface(surface_width, surface_height, color_bytes); m_surface_group[i]->attach_display(this); } } inline c_surface* c_display::alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect) { ASSERT(max_zorder < Z_ORDER_LEVEL_MAX && m_surface_index < m_surface_cnt); (layer_rect == c_rect()) ? m_surface_group[m_surface_index]->set_surface(max_zorder, c_rect(0, 0, m_width, m_height)) : m_surface_group[m_surface_index]->set_surface(max_zorder, layer_rect); return m_surface_group[m_surface_index++]; } inline int c_display::swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset) { int surface_width = s0->m_width; int surface_height = s0->m_height; if (offset < 0 || offset > surface_width || y0 < 0 || y0 >= surface_height || y1 < 0 || y1 >= surface_height || x0 < 0 || x0 >= surface_width || x1 < 0 || x1 >= surface_width) { ASSERT(false); return -1; } int width = (x1 - x0 + 1); if (width < 0 || width > surface_width || width < offset) { ASSERT(false); return -1; } x0 = (x0 >= m_width) ? (m_width - 1) : x0; x1 = (x1 >= m_width) ? (m_width - 1) : x1; y0 = (y0 >= m_height) ? (m_height - 1) : y0; y1 = (y1 >= m_height) ? (m_height - 1) : y1; if (m_phy_fb) { for (int y = y0; y <= y1; y++) { //Left surface char* addr_s = ((char*)(s0->m_fb) + (y * surface_width + x0 + offset) * m_color_bytes); char* addr_d = ((char*)(m_phy_fb)+(y * m_width + x0) * m_color_bytes); memcpy(addr_d, addr_s, (width - offset) * m_color_bytes); //Right surface addr_s = ((char*)(s1->m_fb) + (y * surface_width + x0) * m_color_bytes); addr_d = ((char*)(m_phy_fb)+(y * m_width + x0 + (width - offset)) * m_color_bytes); memcpy(addr_d, addr_s, offset * m_color_bytes); } } else if (m_color_bytes == 2) { void(*draw_pixel)(int x, int y, unsigned int rgb) = m_driver->draw_pixel; for (int y = y0; y <= y1; y++) { //Left surface for (int x = x0; x <= (x1 - offset); x++) { draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s0->m_fb)[y * m_width + x + offset])); } //Right surface for (int x = x1 - offset; x <= x1; x++) { draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s1->m_fb)[y * m_width + x + offset - x1 + x0])); } } } else //m_color_bytes == 3/4... { void(*draw_pixel)(int x, int y, unsigned int rgb) = m_driver->draw_pixel; for (int y = y0; y <= y1; y++) { //Left surface for (int x = x0; x <= (x1 - offset); x++) { draw_pixel(x, y, ((unsigned int*)s0->m_fb)[y * m_width + x + offset]); } //Right surface for (int x = x1 - offset; x <= x1; x++) { draw_pixel(x, y, ((unsigned int*)s1->m_fb)[y * m_width + x + offset - x1 + x0]); } } } m_phy_write_index++; return 0; } ================================================ FILE: src/core/image.h ================================================ #pragma once #include "../core/api.h" #include "../core/resource.h" #include "../core/display.h" #define DEFAULT_MASK_COLOR 0xFF080408 class c_surface; class c_image_operator { public: virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; }; class c_bitmap_operator : public c_image_operator { public: virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { ASSERT(image_info); BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; unsigned short* lower_fb_16 = 0; unsigned int* lower_fb_32 = 0; int lower_fb_width = 0; c_rect lower_fb_rect; if (z_order >= Z_ORDER_LEVEL_1) { lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; lower_fb_rect = surface->m_layers[z_order - 1].rect; lower_fb_width = lower_fb_rect.width(); } unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); int xsize = pBitmap->width; int ysize = pBitmap->height; const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; int color_bytes = surface->m_color_bytes; for (int y_ = y; y_ < y + ysize; y_++) { for (int x_ = x; x_ < x + xsize; x_++) { unsigned int rgb = *pData++; if (mask_rgb_16 == rgb) { if (lower_fb_rect.pt_in_rect(x_, y_)) {//show lower layer surface->draw_pixel(x_, y_, (color_bytes == 4) ? lower_fb_32[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)] : GL_RGB_16_to_32(lower_fb_16[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)]), z_order); } } else { surface->draw_pixel(x_, y_, GL_RGB_16_to_32(rgb), z_order); } } } } virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { ASSERT(image_info); BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; if (0 == pBitmap || (src_x + width > pBitmap->width) || (src_y + height > pBitmap->height)) { return; } unsigned short* lower_fb_16 = 0; unsigned int* lower_fb_32 = 0; int lower_fb_width = 0; c_rect lower_fb_rect; if (z_order >= Z_ORDER_LEVEL_1) { lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; lower_fb_rect = surface->m_layers[z_order - 1].rect; lower_fb_width = lower_fb_rect.width(); } unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; int color_bytes = surface->m_color_bytes; for (int y_ = 0; y_ < height; y_++) { const unsigned short* p = &pData[src_x + (src_y + y_) * pBitmap->width]; for (int x_ = 0; x_ < width; x_++) { unsigned int rgb = *p++; if (mask_rgb_16 == rgb) { if (lower_fb_rect.pt_in_rect(x + x_, y + y_)) {//show lower layer surface->draw_pixel(x + x_, y + y_, (color_bytes == 4) ? lower_fb_32[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left] : GL_RGB_16_to_32(lower_fb_16[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left]), z_order); } } else { surface->draw_pixel(x + x_, y + y_, GL_RGB_16_to_32(rgb), z_order); } } } } }; class c_image { public: static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { image_operator->draw_image(surface, z_order, image_info, x, y, mask_rgb); } static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) { image_operator->draw_image(surface, z_order, image_info, x, y, src_x, src_y, width, height, mask_rgb); } static c_image_operator* image_operator; }; ================================================ FILE: src/core/resource.h ================================================ #pragma once //BITMAP typedef struct struct_bitmap_info { unsigned short width; unsigned short height; unsigned short color_bits;//support 16 bits only const unsigned short* pixel_color_array; } BITMAP_INFO; //FONT typedef struct struct_lattice { unsigned int utf8_code; unsigned char width; const unsigned char* pixel_buffer; } LATTICE; typedef struct struct_lattice_font_info { unsigned char height; unsigned int count; LATTICE* lattice_array; } LATTICE_FONT_INFO; ================================================ FILE: src/core/theme.h ================================================ #pragma once #include "../core/api.h" #include "../core/resource.h" //Rebuild gui library once you change this file enum FONT_LIST { FONT_NULL, FONT_DEFAULT, FONT_CUSTOM1, FONT_CUSTOM2, FONT_CUSTOM3, FONT_CUSTOM4, FONT_CUSTOM5, FONT_CUSTOM6, FONT_MAX }; enum IMAGE_LIST { IMAGE_CUSTOM1, IMAGE_CUSTOM2, IMAGE_CUSTOM3, IMAGE_CUSTOM4, IMAGE_CUSTOM5, IMAGE_CUSTOM6, IMAGE_MAX }; enum COLOR_LIST { COLOR_WND_FONT, COLOR_WND_NORMAL, COLOR_WND_PUSHED, COLOR_WND_FOCUS, COLOR_WND_BORDER, COLOR_CUSTOME1, COLOR_CUSTOME2, COLOR_CUSTOME3, COLOR_CUSTOME4, COLOR_CUSTOME5, COLOR_CUSTOME6, COLOR_MAX }; class c_theme { public: static int add_font(FONT_LIST index, const void* font) { if (index >= FONT_MAX) { ASSERT(false); return -1; } s_font_map[index] = font; return 0; } static const void* get_font(FONT_LIST index) { if (index >= FONT_MAX) { ASSERT(false); return 0; } return s_font_map[index]; } static int add_image(IMAGE_LIST index, const void* image_info) { if (index >= IMAGE_MAX) { ASSERT(false); return -1; } s_image_map[index] = image_info; return 0; } static const void* get_image(IMAGE_LIST index) { if (index >= IMAGE_MAX) { ASSERT(false); return 0; } return s_image_map[index]; } static int add_color(COLOR_LIST index, const unsigned int color) { if (index >= COLOR_MAX) { ASSERT(false); return -1; } s_color_map[index] = color; return 0; } static const unsigned int get_color(COLOR_LIST index) { if (index >= COLOR_MAX) { ASSERT(false); return 0; } return s_color_map[index]; } private: static const void* s_font_map[FONT_MAX]; static const void* s_image_map[IMAGE_MAX]; static unsigned int s_color_map[COLOR_MAX]; }; ================================================ FILE: src/core/wnd.h ================================================ #pragma once #include "../core/api.h" #include "../core/resource.h" #include "../core/display.h" class c_wnd; class c_surface; typedef enum { ATTR_VISIBLE = 0x40000000L, ATTR_FOCUS = 0x20000000L, ATTR_PRIORITY = 0x10000000L// Handle touch action at high priority }WND_ATTRIBUTION; typedef enum { STATUS_NORMAL, STATUS_PUSHED, STATUS_FOCUSED, STATUS_DISABLED }WND_STATUS; typedef enum { NAV_FORWARD, NAV_BACKWARD, NAV_ENTER }NAVIGATION_KEY; typedef enum { TOUCH_DOWN, TOUCH_UP }TOUCH_ACTION; typedef struct struct_wnd_tree { c_wnd* p_wnd;//window instance unsigned int resource_id;//ID const char* str;//caption short x;//position x short y;//position y short width; short height; struct struct_wnd_tree* p_child_tree;//sub tree }WND_TREE; typedef void (c_wnd::*WND_CALLBACK)(int, int); class c_wnd { public: c_wnd() : m_status(STATUS_NORMAL), m_attr((WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)), m_parent(0), m_top_child(0), m_prev_sibling(0), m_next_sibling(0), m_str(0), m_font_color(0), m_bg_color(0), m_id(0), m_z_order(Z_ORDER_LEVEL_0), m_focus_child(0), m_surface(0) {}; virtual ~c_wnd() {}; virtual int connect(c_wnd *parent, unsigned short resource_id, const char* str, short x, short y, short width, short height, WND_TREE* p_child_tree = 0) { if (0 == resource_id) { ASSERT(false); return -1; } m_id = resource_id; set_str(str); m_parent = parent; m_status = STATUS_NORMAL; if (parent) { m_z_order = parent->m_z_order; m_surface = parent->m_surface; } if (0 == m_surface) { ASSERT(false); return -2; } /* (cs.x = x * 1024 / 768) for 1027*768=>800*600 quickly*/ m_wnd_rect.m_left = x; m_wnd_rect.m_top = y; m_wnd_rect.m_right = (x + width - 1); m_wnd_rect.m_bottom = (y + height - 1); pre_create_wnd(); if (0 != parent) { parent->add_child_2_tail(this); } if (load_child_wnd(p_child_tree) >= 0) { on_init_children(); } return 0; } void disconnect() { if (0 != m_top_child) { c_wnd* child = m_top_child; c_wnd* next_child = 0; while (child) { next_child = child->m_next_sibling; child->disconnect(); child = next_child; } } if (0 != m_parent) { m_parent->unlink_child(this); } m_focus_child = 0; m_attr = WND_ATTRIBUTION(0); } virtual void on_init_children() {} virtual void on_paint() {} virtual void show_window() { if (ATTR_VISIBLE == (m_attr & ATTR_VISIBLE)) { on_paint(); c_wnd* child = m_top_child; if (0 != child) { while (child) { child->show_window(); child = child->m_next_sibling; } } } } unsigned short get_id() const { return m_id; } int get_z_order() { return m_z_order; } c_wnd* get_wnd_ptr(unsigned short id) const { c_wnd* child = m_top_child; while (child) { if (child->get_id() == id) { break; } child = child->m_next_sibling; } return child; } unsigned int get_attr() const { return m_attr; } void set_str(const char* str) { m_str = str; } void set_attr(WND_ATTRIBUTION attr) { m_attr = attr; } bool is_focus_wnd() const { return ((m_attr & ATTR_VISIBLE) && (m_attr & ATTR_FOCUS)) ? true : false; } void set_font_color(unsigned int color) { m_font_color = color; } unsigned int get_font_color() { return m_font_color; } void set_bg_color(unsigned int color) { m_bg_color = color; } unsigned int get_bg_color() { return m_bg_color; } void set_font_type(const LATTICE_FONT_INFO *font_type) { m_font = font_type; } const void* get_font_type() { return m_font; } void get_wnd_rect(c_rect &rect) const { rect = m_wnd_rect; } void get_screen_rect(c_rect &rect) const { int l = 0; int t = 0; wnd2screen(l, t); rect.set_rect(l, t, m_wnd_rect.width(), m_wnd_rect.height()); } c_wnd* set_child_focus(c_wnd *focus_child) { ASSERT(0 != focus_child); ASSERT(focus_child->m_parent == this); c_wnd* old_focus_child = m_focus_child; if (focus_child->is_focus_wnd()) { if (focus_child != old_focus_child) { if (old_focus_child) { old_focus_child->on_kill_focus(); } m_focus_child = focus_child; m_focus_child->on_focus(); } } return m_focus_child; } c_wnd* get_parent() const { return m_parent; } c_wnd* get_last_child() const { if (0 == m_top_child) { return 0; } c_wnd* child = m_top_child; while (child->m_next_sibling) { child = child->m_next_sibling; } return child; } int unlink_child(c_wnd *child) { if ((0 == child) || (this != child->m_parent)) { return -1; } if (0 == m_top_child) { return -2; } bool find = false; c_wnd* tmp_child = m_top_child; if (tmp_child == child) { m_top_child = child->m_next_sibling; if (0 != child->m_next_sibling) { child->m_next_sibling->m_prev_sibling = 0; } find = true; } else { while (tmp_child->m_next_sibling) { if (child == tmp_child->m_next_sibling) { tmp_child->m_next_sibling = child->m_next_sibling; if (0 != child->m_next_sibling) { child->m_next_sibling->m_prev_sibling = tmp_child; } find = true; break; } tmp_child = tmp_child->m_next_sibling; } } if (true == find) { if (m_focus_child == child) { m_focus_child = 0; } child->m_next_sibling = 0; child->m_prev_sibling = 0; return 1; } else { return 0; } } c_wnd* get_prev_sibling() const { return m_prev_sibling; } c_wnd* get_next_sibling() const { return m_next_sibling; } c_wnd* search_priority_sibling(c_wnd* root) { c_wnd* priority_wnd = 0; while (root) { if ((root->m_attr & ATTR_PRIORITY) && (root->m_attr & ATTR_VISIBLE)) { priority_wnd = root; break; } root = root->m_next_sibling; } return priority_wnd; } virtual void on_touch(int x, int y, TOUCH_ACTION action) { x -= m_wnd_rect.m_left; y -= m_wnd_rect.m_top; c_wnd* priority_wnd = search_priority_sibling(m_top_child); if (priority_wnd) { return priority_wnd->on_touch(x, y, action); } c_wnd* child = m_top_child; while (child) { if (child->is_focus_wnd()) { c_rect rect; child->get_wnd_rect(rect); if (true == rect.pt_in_rect(x, y)) { return child->on_touch(x, y, action); } } child = child->m_next_sibling; } } virtual void on_navigate(NAVIGATION_KEY key) { c_wnd* priority_wnd = search_priority_sibling(m_top_child); if (priority_wnd) { return priority_wnd->on_navigate(key); } if (!is_focus_wnd()) { return; } if (key != NAV_BACKWARD && key != NAV_FORWARD) { if (m_focus_child) { m_focus_child->on_navigate(key); } return; } // Move focus c_wnd* old_focus_wnd = m_focus_child; // No current focus wnd, new one. if (!old_focus_wnd) { c_wnd* child = m_top_child; c_wnd* new_focus_wnd = 0; while (child) { if (child->is_focus_wnd()) { new_focus_wnd = child; new_focus_wnd->m_parent->set_child_focus(new_focus_wnd); child = child->m_top_child; continue; } child = child->m_next_sibling; } return; } // Move focus from old wnd to next wnd c_wnd* next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_next_sibling : old_focus_wnd->m_prev_sibling; while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) {// Search neighbor of old focus wnd next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; } if (!next_focus_wnd) {// Search whole brother wnd next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_parent->m_top_child : old_focus_wnd->m_parent->get_last_child(); while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) { next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; } } if (next_focus_wnd) { next_focus_wnd->m_parent->set_child_focus(next_focus_wnd); } } c_surface* get_surface() { return m_surface; } void set_surface(c_surface* surface) { m_surface = surface; } protected: virtual void pre_create_wnd() {}; void add_child_2_tail(c_wnd *child) { if (0 == child)return; if (child == get_wnd_ptr(child->m_id))return; if (0 == m_top_child) { m_top_child = child; child->m_prev_sibling = 0; child->m_next_sibling = 0; } else { c_wnd* last_child = get_last_child(); if (0 == last_child) { ASSERT(false); } last_child->m_next_sibling = child; child->m_prev_sibling = last_child; child->m_next_sibling = 0; } } void wnd2screen(int &x, int &y) const { c_wnd* parent = m_parent; c_rect rect; x += m_wnd_rect.m_left; y += m_wnd_rect.m_top; while (0 != parent) { parent->get_wnd_rect(rect); x += rect.m_left; y += rect.m_top; parent = parent->m_parent; } } int load_child_wnd(WND_TREE *p_child_tree) { if (0 == p_child_tree) { return 0; } int sum = 0; WND_TREE* p_cur = p_child_tree; while (p_cur->p_wnd) { p_cur->p_wnd->connect(this, p_cur->resource_id, p_cur->str,p_cur->x, p_cur->y, p_cur->width, p_cur->height, p_cur->p_child_tree); p_cur++; sum++; } return sum; } void set_active_child(c_wnd* child) { m_focus_child = child; } virtual void on_focus() {}; virtual void on_kill_focus() {}; protected: unsigned short m_id; WND_STATUS m_status; WND_ATTRIBUTION m_attr; c_rect m_wnd_rect; //position relative to parent window. c_wnd* m_parent; //parent window c_wnd* m_top_child; //the first sub window would be navigated c_wnd* m_prev_sibling; //previous brother c_wnd* m_next_sibling; //next brother c_wnd* m_focus_child; //current focused window const char* m_str; //caption const void* m_font; //font face unsigned int m_font_color; unsigned int m_bg_color; int m_z_order; //the graphic level for rendering c_surface* m_surface; }; ================================================ FILE: src/core/word.h ================================================ #pragma once #include "../core/api.h" #include "../core/resource.h" #include "../core/display.h" #include #include #define VALUE_STR_LEN 16 class c_surface; class c_font_operator { public: virtual void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; virtual void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; virtual void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; virtual void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; virtual int get_str_size(const void* string, const void* font, int& width, int& height) = 0; void get_string_pos(const void* string, const void* font, c_rect rect, unsigned int align_type, int& x, int& y) { int x_size, y_size; get_str_size(string, font, x_size, y_size); int height = rect.m_bottom - rect.m_top + 1; int width = rect.m_right - rect.m_left + 1; x = y = 0; switch (align_type & ALIGN_HMASK) { case ALIGN_HCENTER: //m_text_org_x=0 if (width > x_size) { x = (width - x_size) / 2; } break; case ALIGN_LEFT: x = 0; break; case ALIGN_RIGHT: //m_text_org_x=0 if (width > x_size) { x = width - x_size; } break; default: ASSERT(0); break; } switch (align_type & ALIGN_VMASK) { case ALIGN_VCENTER: //m_text_org_y=0 if (height > y_size) { y = (height - y_size) / 2; } break; case ALIGN_TOP: y = 0; break; case ALIGN_BOTTOM: //m_text_org_y=0 if (height > y_size) { y = height - y_size; } break; default: ASSERT(0); break; } } }; class c_lattice_font_op : public c_font_operator { public: void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) { const char* s = (const char*)string; if (0 == s) { return; } int offset = 0; unsigned int utf8_code; while (*s) { s += get_utf8_code(s, utf8_code); offset += draw_single_char(surface, z_order, utf8_code, (x + offset), y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); } } void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) { const char* s = (const char*)string; if (0 == s) { return; } int x, y; get_string_pos(s, (const LATTICE_FONT_INFO*)font, rect, align_type, x, y); draw_string(surface, z_order, string, rect.m_left + x, rect.m_top + y, font, font_color, bg_color); } void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) { char buf[VALUE_STR_LEN]; value_2_string(value, dot_position, buf, VALUE_STR_LEN); draw_string(surface, z_order, buf, x, y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); } void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) { char buf[VALUE_STR_LEN]; value_2_string(value, dot_position, buf, VALUE_STR_LEN); draw_string_in_rect(surface, z_order, buf, rect, (const LATTICE_FONT_INFO*)font, font_color, bg_color, align_type); } int get_str_size(const void *string, const void* font, int& width, int& height) { const char* s = (const char*)string; if (0 == s || 0 == font) { width = height = 0; return -1; } int lattice_width = 0; unsigned int utf8_code; int utf8_bytes; while (*s) { utf8_bytes = get_utf8_code(s, utf8_code); const LATTICE* p_lattice = get_lattice((const LATTICE_FONT_INFO*)font, utf8_code); lattice_width += p_lattice ? p_lattice->width : ((const LATTICE_FONT_INFO*)font)->height; s += utf8_bytes; } width = lattice_width; height = ((const LATTICE_FONT_INFO*)font)->height; return 0; } private: void value_2_string(int value, int dot_position, char* buf, int len) { memset(buf, 0, len); switch (dot_position) { case 0: sprintf(buf, "%d", value); break; case 1: sprintf(buf, "%.1f", value * 1.0 / 10); break; case 2: sprintf(buf, "%.2f", value * 1.0 / 100); break; case 3: sprintf(buf, "%.3f", value * 1.0 / 1000); break; default: ASSERT(false); break; } } int draw_single_char(c_surface* surface, int z_order, unsigned int utf8_code, int x, int y, const LATTICE_FONT_INFO* font, unsigned int font_color, unsigned int bg_color) { unsigned int error_color = 0xFFFFFFFF; if (font) { const LATTICE* p_lattice = get_lattice(font, utf8_code); if (p_lattice) { draw_lattice(surface, z_order, x, y, p_lattice->width, font->height, p_lattice->pixel_buffer, font_color, bg_color); return p_lattice->width; } } else { error_color = GL_RGB(255, 0, 0); } //lattice/font not found, draw "X" int len = 16; for (int y_ = 0; y_ < len; y_++) { for (int x_ = 0; x_ < len; x_++) { int diff = (x_ - y_); int sum = (x_ + y_); (diff == 0 || diff == -1 || diff == 1 || sum == len || sum == (len - 1) || sum == (len + 1)) ? surface->draw_pixel((x + x_), (y + y_), error_color, z_order) : surface->draw_pixel((x + x_), (y + y_), 0, z_order); } } return len; } void draw_lattice(c_surface* surface, int z_order, int x, int y, int width, int height, const unsigned char* p_data, unsigned int font_color, unsigned int bg_color) { unsigned int r, g, b, rgb; unsigned char blk_value = *p_data++; unsigned char blk_cnt = *p_data++; b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; rgb = GL_RGB(r, g, b); for (int y_ = 0; y_ < height; y_++) { for (int x_ = 0; x_ < width; x_++) { ASSERT(blk_cnt); if (0x00 == blk_value) { if (GL_ARGB_A(bg_color)) { surface->draw_pixel(x + x_, y + y_, bg_color, z_order); } } else { surface->draw_pixel((x + x_), (y + y_), rgb, z_order); } if (--blk_cnt == 0) {//reload new block blk_value = *p_data++; blk_cnt = *p_data++; b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; rgb = GL_RGB(r, g, b); } } } } const LATTICE* get_lattice(const LATTICE_FONT_INFO* font, unsigned int utf8_code) { int first = 0; int last = font->count - 1; int middle = (first + last) / 2; while (first <= last) { if (font->lattice_array[middle].utf8_code < utf8_code) first = middle + 1; else if (font->lattice_array[middle].utf8_code == utf8_code) { return &font->lattice_array[middle]; } else { last = middle - 1; } middle = (first + last) / 2; } return 0; } static int get_utf8_code(const char* s, unsigned int& output_utf8_code) { static unsigned char s_utf8_length_table[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 }; unsigned char* us = (unsigned char*)s; int utf8_bytes = s_utf8_length_table[*us]; switch (utf8_bytes) { case 1: output_utf8_code = *us; break; case 2: output_utf8_code = (*us << 8) | (*(us + 1)); break; case 3: output_utf8_code = (*us << 16) | ((*(us + 1)) << 8) | *(us + 2); break; case 4: output_utf8_code = (*us << 24) | ((*(us + 1)) << 16) | (*(us + 2) << 8) | *(us + 3); break; default: ASSERT(false); break; } return utf8_bytes; } }; class c_word { public: static void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color)//string: char or wchar_t { fontOperator->draw_string(surface, z_order, string, x, y, font, font_color, bg_color); } static void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT)//string: char or wchar_t { fontOperator->draw_string_in_rect(surface, z_order, string, rect, font, font_color, bg_color, align_type); } static void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) { fontOperator->draw_value_in_rect(surface, z_order, value, dot_position, rect, font, font_color, bg_color, align_type); } static void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) { fontOperator->draw_value(surface, z_order, value, dot_position, x, y, font, font_color, bg_color); } static int get_str_size(const void* string, const void* font, int& width, int& height) { return fontOperator->get_str_size(string, font, width, height); } static c_font_operator* fontOperator; }; ================================================ FILE: src/widgets/button.h ================================================ #pragma once #include "../core/api.h" #include "../core/wnd.h" #include "../core/resource.h" #include "../core/word.h" #include "../core/display.h" #include "../core/theme.h" class c_button : public c_wnd { public: void set_on_click(WND_CALLBACK on_click) { this->on_click = on_click; } protected: virtual void on_paint() { c_rect rect; get_screen_rect(rect); switch (m_status) { case STATUS_NORMAL: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); if (m_str) { c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); } break; case STATUS_FOCUSED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); if (m_str) { c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); } break; case STATUS_PUSHED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); if (m_str) { c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); } break; default: ASSERT(false); break; } } virtual void on_focus() { m_status = STATUS_FOCUSED; on_paint(); } virtual void on_kill_focus() { m_status = STATUS_NORMAL; on_paint(); } virtual void pre_create_wnd() { on_click = 0; m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); } virtual void on_touch(int x, int y, TOUCH_ACTION action) { if (action == TOUCH_DOWN) { m_parent->set_child_focus(this); m_status = STATUS_PUSHED; on_paint(); } else { m_status = STATUS_FOCUSED; on_paint(); if(on_click) { (m_parent->*(on_click))(m_id, 0); } } } virtual void on_navigate(NAVIGATION_KEY key) { switch (key) { case NAV_ENTER: on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); break; case NAV_FORWARD: case NAV_BACKWARD: break; } return c_wnd::on_navigate(key); } WND_CALLBACK on_click; }; ================================================ FILE: src/widgets/dialog.h ================================================ #pragma once #include "../core/api.h" #include "../core/wnd.h" #include "../core/display.h" #include "../core/resource.h" #include "../core/word.h" #include "../core/theme.h" class c_surface; class c_dialog; typedef struct { c_dialog* dialog; c_surface* surface; } DIALOG_ARRAY; class c_dialog : public c_wnd { public: static int open_dialog(c_dialog* p_dlg, bool modal_mode = true) { if (0 == p_dlg) { ASSERT(false); return 0; } c_dialog* cur_dlg = get_the_dialog(p_dlg->get_surface()); if (cur_dlg == p_dlg) { return 1; } if (cur_dlg) { cur_dlg->set_attr(WND_ATTRIBUTION(0)); } c_rect rc; p_dlg->get_screen_rect(rc); p_dlg->get_surface()->activate_layer(rc, p_dlg->m_z_order); p_dlg->set_attr(modal_mode ? (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY) : (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)); p_dlg->show_window(); p_dlg->set_me_the_dialog(); return 1; } static int close_dialog(c_surface* surface) { c_dialog* dlg = get_the_dialog(surface); if (0 == dlg) { return 0; } dlg->set_attr(WND_ATTRIBUTION(0)); surface->activate_layer(c_rect(), dlg->m_z_order);//inactivate the layer of dialog by empty rect. //clear the dialog for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == surface) { ms_the_dialogs[i].dialog = 0; return 1; } } ASSERT(false); return -1; } static c_dialog* get_the_dialog(c_surface* surface) { for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == surface) { return ms_the_dialogs[i].dialog; } } return 0; } protected: virtual void pre_create_wnd() { m_attr = WND_ATTRIBUTION(0);// no focus/visible m_z_order = Z_ORDER_LEVEL_1; m_bg_color = GL_RGB(33, 42, 53); } virtual void on_paint() { c_rect rect; get_screen_rect(rect); m_surface->fill_rect(rect, m_bg_color, m_z_order); if (m_str) { c_word::draw_string(m_surface, m_z_order, m_str, rect.m_left + 35, rect.m_top, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0)); } } private: int set_me_the_dialog() { c_surface* surface = get_surface(); for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == surface) { ms_the_dialogs[i].dialog = this; return 0; } } for (int i = 0; i < SURFACE_CNT_MAX; i++) { if (ms_the_dialogs[i].surface == 0) { ms_the_dialogs[i].dialog = this; ms_the_dialogs[i].surface = surface; return 1; } } ASSERT(false); return -2; } static DIALOG_ARRAY ms_the_dialogs[SURFACE_CNT_MAX]; }; ================================================ FILE: src/widgets/edit.h ================================================ #pragma once #include "../core/api.h" #include "../core/wnd.h" #include "../core/resource.h" #include "../core/word.h" #include "../core/display.h" #include "../core/theme.h" #include "../widgets/button.h" #include "../widgets/label.h" #include "../widgets/keyboard.h" #include #define MAX_EDIT_STRLEN 32 #define IDD_KEY_BOARD 0x1 class c_edit : public c_wnd { friend class c_keyboard; public: const char* get_text(){return m_str;} void set_text(const char* str) { if (str != 0 && strlen(str) < sizeof(m_str)) { strcpy(m_str, str); } } void set_keyboard_style(KEYBOARD_STYLE kb_sytle) { m_kb_style = kb_sytle; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); m_kb_style = STYLE_ALL_BOARD; m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); memset(m_str_input, 0, sizeof(m_str_input)); memset(m_str, 0, sizeof(m_str)); set_text(c_wnd::m_str); } virtual void on_paint() { c_rect rect, kb_rect; get_screen_rect(rect); s_keyboard.get_screen_rect(kb_rect); switch (m_status) { case STATUS_NORMAL: if ((s_keyboard.get_attr()&ATTR_VISIBLE) == ATTR_VISIBLE) { s_keyboard.close_keyboard(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_FOCUSED: if ((s_keyboard.get_attr()&ATTR_VISIBLE) == ATTR_VISIBLE) { s_keyboard.close_keyboard(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_PUSHED: if ((s_keyboard.get_attr()&ATTR_VISIBLE) != ATTR_VISIBLE) { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); s_keyboard.open_keyboard(this, IDD_KEY_BOARD, m_kb_style, WND_CALLBACK(&c_edit::on_key_board_click)); } m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_PUSHED), m_parent->get_z_order()); m_surface->draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_BORDER), m_parent->get_z_order(), 2); strlen(m_str_input) ? c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str_input, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER) : c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); break; default: ASSERT(false); } } virtual void on_focus() { m_status = STATUS_FOCUSED; on_paint(); } virtual void on_kill_focus() { m_status = STATUS_NORMAL; on_paint(); } virtual void on_navigate(NAVIGATION_KEY key) { switch (key) { case NAV_ENTER: (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : (on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN), on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP)); return; case NAV_BACKWARD: case NAV_FORWARD: return (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : c_wnd::on_navigate(key); } } virtual void on_touch(int x, int y, TOUCH_ACTION action) { (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); } void on_key_board_click(int id, int param) { switch (param) { case CLICK_CHAR: strcpy(m_str_input, s_keyboard.get_str()); on_paint(); break; case CLICK_ENTER: if (strlen(m_str_input)) { memcpy(m_str, m_str_input, sizeof(m_str_input)); } m_status = STATUS_FOCUSED; on_paint(); break; case CLICK_ESC: memset(m_str_input, 0, sizeof(m_str_input)); m_status = STATUS_FOCUSED; on_paint(); break; default: ASSERT(false); break; } } private: void on_touch_down(int x, int y) { c_rect kb_rect_relate_2_edit_parent; s_keyboard.get_wnd_rect(kb_rect_relate_2_edit_parent); kb_rect_relate_2_edit_parent.m_left += m_wnd_rect.m_left; kb_rect_relate_2_edit_parent.m_right += m_wnd_rect.m_left; kb_rect_relate_2_edit_parent.m_top += m_wnd_rect.m_top; kb_rect_relate_2_edit_parent.m_bottom += m_wnd_rect.m_top; if (m_wnd_rect.pt_in_rect(x, y)) {//click edit box if (STATUS_NORMAL == m_status) { m_parent->set_child_focus(this); } } else if (kb_rect_relate_2_edit_parent.pt_in_rect(x, y)) {//click key board c_wnd::on_touch(x, y, TOUCH_DOWN); } else { if (STATUS_PUSHED == m_status) { m_status = STATUS_FOCUSED; on_paint(); } } } void on_touch_up(int x, int y) { if (STATUS_FOCUSED == m_status) { m_status = STATUS_PUSHED; on_paint(); } else if (STATUS_PUSHED == m_status) { if (m_wnd_rect.pt_in_rect(x, y)) {//click edit box m_status = STATUS_FOCUSED; on_paint(); } else { c_wnd::on_touch(x, y, TOUCH_UP); } } } static c_keyboard s_keyboard; KEYBOARD_STYLE m_kb_style; char m_str_input[MAX_EDIT_STRLEN]; char m_str[MAX_EDIT_STRLEN]; }; ================================================ FILE: src/widgets/keyboard.h ================================================ #pragma once #include "../core/api.h" #include "../core/resource.h" #include "../core/word.h" #include "../core/wnd.h" #include "../core/display.h" #include "../core/theme.h" #include "../widgets/button.h" #include //Changing key width/height will change the width/height of keyboard #define KEY_WIDTH 65 #define KEY_HEIGHT 38 #define KEYBOARD_WIDTH ((KEY_WIDTH + 2) * 10) #define KEYBOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) #define NUM_BOARD_WIDTH ((KEY_WIDTH + 2) * 4) #define NUM_BOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) #define CAPS_WIDTH (KEY_WIDTH * 3 / 2) #define DEL_WIDTH (KEY_WIDTH * 3 / 2 + 1) #define ESC_WIDTH (KEY_WIDTH * 2 + 2) #define SWITCH_WIDTH (KEY_WIDTH * 3 / 2 ) #define SPACE_WIDTH (KEY_WIDTH * 3 + 2 * 2) #define DOT_WIDTH (KEY_WIDTH * 3 / 2 + 3) #define ENTER_WIDTH (KEY_WIDTH * 2 + 2) #define POS_X(c) ((KEY_WIDTH * c) + (c + 1) * 2) #define POS_Y(r) ((KEY_HEIGHT * r) + (r + 1) * 2) #define KEYBOARD_CLICK 0x5014 #define ON_KEYBORAD_UPDATE(func) \ {MSG_TYPE_WND, KEYBOARD_CLICK, 0, msgCallback(&func)}, typedef enum { STATUS_UPPERCASE, STATUS_LOWERCASE }KEYBOARD_STATUS; typedef enum { STYLE_ALL_BOARD, STYLE_NUM_BOARD }KEYBOARD_STYLE; typedef enum { CLICK_CHAR, CLICK_ENTER, CLICK_ESC }CLICK_STATUS; extern WND_TREE g_key_board_children[]; extern WND_TREE g_number_board_children[]; class c_keyboard: public c_wnd { public: c_keyboard() { m_attr = WND_ATTRIBUTION(0); } int open_keyboard(c_wnd *user, unsigned short resource_id, KEYBOARD_STYLE style, WND_CALLBACK on_click) { c_rect user_rect; user->get_wnd_rect(user_rect); if ((style != STYLE_ALL_BOARD) && (style != STYLE_NUM_BOARD)) { ASSERT(false); return -1; } if (style == STYLE_ALL_BOARD) {//Place keyboard at the bottom of user's parent window. c_rect user_parent_rect; user->get_parent()->get_wnd_rect(user_parent_rect); c_wnd::connect(user, resource_id, 0, (0 - user_rect.m_left), (user_parent_rect.height() - user_rect.m_top - KEYBOARD_HEIGHT - 1), KEYBOARD_WIDTH, KEYBOARD_HEIGHT, g_key_board_children); } else if (style == STYLE_NUM_BOARD) {//Place keyboard below the user window. c_wnd::connect(user, resource_id, 0, 0, user_rect.height(), NUM_BOARD_WIDTH, NUM_BOARD_HEIGHT, g_number_board_children); } m_on_click = on_click; c_rect rc; get_screen_rect(rc); m_surface->activate_layer(rc, m_z_order); show_window(); return 0; } void close_keyboard() { c_wnd::disconnect(); m_surface->activate_layer(c_rect(), m_z_order);//inactivate the layer of keyboard by empty rect. } virtual void on_init_children() { c_wnd* child = m_top_child; if (0 != child) { while (child) { ((c_button*)child)->set_on_click(WND_CALLBACK(&c_keyboard::on_key_clicked)); child = child->get_next_sibling(); } } } KEYBOARD_STATUS get_cap_status(){return m_cap_status;} char* get_str() { return m_str; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); m_cap_status = STATUS_UPPERCASE; m_z_order = m_surface->get_max_z_order(); memset(m_str, 0, sizeof(m_str)); m_str_len = 0; } virtual void on_paint() { c_rect rect; get_screen_rect(rect); m_surface->fill_rect(rect, GL_RGB(0, 0, 0), m_z_order); } void on_key_clicked(int id, int param) { switch (id) { case 0x14: on_caps_clicked(id, param); break; case '\n': on_enter_clicked(id, param); break; case 0x1B: on_esc_clicked(id, param); break; case 0x7F: on_del_clicked(id, param); break; default: on_char_clicked(id, param); break; } } void on_char_clicked(int id, int param) {//id = char ascii code. if (m_str_len >= sizeof(m_str)) { return; } if ((id >= '0' && id <= '9') || id == ' ' || id == '.') { goto InputChar; } if (id >= 'A' && id <= 'Z') { if (STATUS_LOWERCASE == m_cap_status) { id += 0x20; } goto InputChar; } if (id == 0x90) return;//TBD ASSERT(false); InputChar: m_str[m_str_len++] = id; (m_parent->*(m_on_click))(m_id, CLICK_CHAR); } void on_del_clicked(int id, int param) { if (m_str_len <= 0) { return; } m_str[--m_str_len] = 0; (m_parent->*(m_on_click))(m_id, CLICK_CHAR); } void on_caps_clicked(int id, int param) { m_cap_status = (m_cap_status == STATUS_LOWERCASE) ? STATUS_UPPERCASE : STATUS_LOWERCASE; show_window(); } void on_enter_clicked(int id, int param) { memset(m_str, 0, sizeof(m_str)); (m_parent->*(m_on_click))(m_id, CLICK_ENTER); } void on_esc_clicked(int id, int param) { memset(m_str, 0, sizeof(m_str)); (m_parent->*(m_on_click))(m_id, CLICK_ESC); } private: char m_str[32]; int m_str_len; KEYBOARD_STATUS m_cap_status; WND_CALLBACK m_on_click; }; class c_keyboard_button : public c_button { protected: virtual void on_paint() { c_rect rect; get_screen_rect(rect); switch (m_status) { case STATUS_NORMAL: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); break; case STATUS_FOCUSED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); break; case STATUS_PUSHED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); break; default: ASSERT(false); break; } if (m_id == 0x14) { return c_word::draw_string_in_rect(m_surface, m_z_order, "Caps", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == 0x1B) { return c_word::draw_string_in_rect(m_surface, m_z_order, "Esc", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == ' ') { return c_word::draw_string_in_rect(m_surface, m_z_order, "Space", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == '\n') { return c_word::draw_string_in_rect(m_surface, m_z_order, "Enter", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == '.') { return c_word::draw_string_in_rect(m_surface, m_z_order, ".", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == 0x7F) { return c_word::draw_string_in_rect(m_surface, m_z_order, "Back", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } else if (m_id == 0x90) { return c_word::draw_string_in_rect(m_surface, m_z_order, "?123", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } char letter[] = { 0, 0 }; if (m_id >= 'A' && m_id <= 'Z') { letter[0] = (((c_keyboard*)m_parent)->get_cap_status() == STATUS_UPPERCASE) ? m_id : (m_id + 0x20); } else if (m_id >= '0' && m_id <= '9') { letter[0] = (char)m_id; } c_word::draw_string_in_rect(m_surface, m_z_order, letter, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER); } }; ================================================ FILE: src/widgets/label.h ================================================ #pragma once #include "../core/api.h" #include "../core/wnd.h" #include "../core/display.h" #include "../core/resource.h" #include "../core/theme.h" #include "../core/word.h" class c_label : public c_wnd { public: virtual void on_paint() { c_rect rect; unsigned int bg_color = m_bg_color ? m_bg_color : m_parent->get_bg_color(); get_screen_rect(rect); if (m_str) { m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, bg_color, m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, bg_color, ALIGN_LEFT | ALIGN_VCENTER); } } protected: virtual void pre_create_wnd() { m_attr = ATTR_VISIBLE; m_font_color = c_theme::get_color(COLOR_WND_FONT); m_font = c_theme::get_font(FONT_DEFAULT); } }; ================================================ FILE: src/widgets/list_box.h ================================================ #pragma once #include "../core/api.h" #include "../core/resource.h" #include "../core/wnd.h" #include "../core/display.h" #include "../core/word.h" #include "../core/theme.h" #include "../widgets/button.h" #include #define MAX_ITEM_NUM 4 #define ITEM_HEIGHT 45 class c_list_box : public c_wnd { public: void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } short get_item_count() { return m_item_total; } int add_item(char* str) { if (m_item_total >= MAX_ITEM_NUM) { ASSERT(false); return -1; } m_item_array[m_item_total++] = str; update_list_size(); return 0; } void clear_item() { m_selected_item = m_item_total = 0; memset(m_item_array, 0, sizeof(m_item_array)); update_list_size(); } void select_item(short index) { if (index < 0 || index >= m_item_total) { ASSERT(false); } m_selected_item = index; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); memset(m_item_array, 0, sizeof(m_item_array)); m_item_total = 0; m_selected_item = 0; m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); } virtual void on_paint() { c_rect rect; get_screen_rect(rect); switch (m_status) { case STATUS_NORMAL: if (m_z_order > m_parent->get_z_order()) { m_surface->activate_layer(c_rect(), m_z_order);//inactivate the layer of list by empty rect. m_z_order = m_parent->get_z_order(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_FOCUSED: if (m_z_order > m_parent->get_z_order()) { m_surface->activate_layer(c_rect(), m_z_order);//inactivate the layer of list by empty rect. m_z_order = m_parent->get_z_order(); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); } m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); break; case STATUS_PUSHED: m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, GL_RGB(2, 124, 165), GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER | ALIGN_VCENTER); //draw list if (m_item_total > 0) { if (m_z_order == m_parent->get_z_order()) { m_z_order++; m_surface->activate_layer(m_list_screen_rect, m_z_order); m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); } show_list(); } break; default: ASSERT(false); } } virtual void on_focus() { m_status = STATUS_FOCUSED; on_paint(); } virtual void on_kill_focus() { m_status = STATUS_NORMAL; on_paint(); } virtual void on_navigate(NAVIGATION_KEY key) { switch (key) { case NAV_ENTER: if (STATUS_PUSHED == m_status) { if(on_change) { (m_parent->*(on_change))(m_id, m_selected_item); } } on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); return; case NAV_BACKWARD: if (m_status != STATUS_PUSHED) { return c_wnd::on_navigate(key); } m_selected_item = (m_selected_item > 0) ? (m_selected_item - 1) : m_selected_item; return show_list(); case NAV_FORWARD: if (m_status != STATUS_PUSHED) { return c_wnd::on_navigate(key); } m_selected_item = (m_selected_item < (m_item_total - 1)) ? (m_selected_item + 1) : m_selected_item; return show_list(); } } virtual void on_touch(int x, int y, TOUCH_ACTION action) { (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); } private: void update_list_size() { m_list_wnd_rect = m_wnd_rect; m_list_wnd_rect.m_top = m_wnd_rect.m_bottom + 1; m_list_wnd_rect.m_bottom = m_list_wnd_rect.m_top + m_item_total * ITEM_HEIGHT; get_screen_rect(m_list_screen_rect); m_list_screen_rect.m_top = m_list_screen_rect.m_bottom + 1; m_list_screen_rect.m_bottom = m_list_screen_rect.m_top + m_item_total * ITEM_HEIGHT; } void show_list() { //draw all items c_rect tmp_rect; for (int i = 0; i < m_item_total; i++) { tmp_rect.m_left = m_list_screen_rect.m_left; tmp_rect.m_right = m_list_screen_rect.m_right; tmp_rect.m_top = m_list_screen_rect.m_top + i * ITEM_HEIGHT; tmp_rect.m_bottom = tmp_rect.m_top + ITEM_HEIGHT; if (m_selected_item == i) { m_surface->fill_rect(tmp_rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); } else { m_surface->fill_rect(tmp_rect, GL_RGB(17, 17, 17), m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, GL_RGB(17, 17, 17), ALIGN_HCENTER | ALIGN_VCENTER); } } } void on_touch_down(int x, int y) { if (m_wnd_rect.pt_in_rect(x, y)) {//click base if (STATUS_NORMAL == m_status) { m_parent->set_child_focus(this); } } else if (m_list_wnd_rect.pt_in_rect(x, y)) {//click extend list c_wnd::on_touch(x, y, TOUCH_DOWN); } else { if (STATUS_PUSHED == m_status) { m_status = STATUS_FOCUSED; on_paint(); if(on_change) { (m_parent->*(on_change))(m_id, m_selected_item); } } } } void on_touch_up(int x, int y) { if (STATUS_FOCUSED == m_status) { m_status = STATUS_PUSHED; on_paint(); } else if (STATUS_PUSHED == m_status) { if (m_wnd_rect.pt_in_rect(x, y)) {//click base m_status = STATUS_FOCUSED; on_paint(); } else if (m_list_wnd_rect.pt_in_rect(x, y)) {//click extend list m_status = STATUS_FOCUSED; select_item((y - m_list_wnd_rect.m_top) / ITEM_HEIGHT); on_paint(); if(on_change) { (m_parent->*(on_change))(m_id, m_selected_item); } } else { c_wnd::on_touch(x, y, TOUCH_UP); } } } short m_selected_item; short m_item_total; char* m_item_array[MAX_ITEM_NUM]; c_rect m_list_wnd_rect; //rect relative to parent wnd. c_rect m_list_screen_rect; //rect relative to physical screen(frame buffer) WND_CALLBACK on_change; }; ================================================ FILE: src/widgets/slide_group.h ================================================ #pragma once #include "../core/api.h" #include "../core/display.h" #include "../core/wnd.h" #include "../widgets/dialog.h" #include #define MAX_PAGES 5 class c_gesture; class c_slide_group : public c_wnd { public: inline c_slide_group(); int set_active_slide(int index, bool is_redraw = true) { if (index >= MAX_PAGES || index < 0) { return -1; } if (0 == m_slides[index]) { return -2; } m_active_slide_index = index; for (int i = 0; i < MAX_PAGES; i++) { if (m_slides[i] == 0) { continue; } if (i == index) { m_slides[i]->get_surface()->set_active(true); add_child_2_tail(m_slides[i]); if (is_redraw) { c_rect rc; get_screen_rect(rc); m_slides[i]->get_surface()->flush_screen(rc.m_left, rc.m_top, rc.m_right, rc.m_bottom); } } else { m_slides[i]->get_surface()->set_active(false); } } return 0; } c_wnd* get_slide(int index){return m_slides[index];} c_wnd* get_active_slide(){return m_slides[m_active_slide_index];} int get_active_slide_index(){return m_active_slide_index;} int add_slide(c_wnd* slide, unsigned short resource_id, short x, short y, short width, short height, WND_TREE* p_child_tree = 0, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0) { if (0 == slide) { return -1; } c_surface* old_surface = get_surface(); c_surface* new_surface = old_surface->get_display()->alloc_surface(max_zorder); new_surface->set_active(false); set_surface(new_surface); slide->connect(this, resource_id, 0, x, y, width, height, p_child_tree); set_surface(old_surface); int i = 0; while (i < MAX_PAGES) { if (m_slides[i] == slide) {//slide has lived ASSERT(false); return -2; } i++; } //new slide i = 0; while (i < MAX_PAGES) { if (m_slides[i] == 0) { m_slides[i] = slide; slide->show_window(); return 0; } i++; } //no more slide can be add ASSERT(false); return -3; } void disabel_all_slide() { for (int i = 0; i < MAX_PAGES; i++) { if (m_slides[i]) { m_slides[i]->get_surface()->set_active(false); } } } inline virtual void on_touch(int x, int y, TOUCH_ACTION action); virtual void on_navigate(NAVIGATION_KEY key) { if (m_slides[m_active_slide_index]) { m_slides[m_active_slide_index]->on_navigate(key); } } protected: c_wnd* m_slides[MAX_PAGES]; int m_active_slide_index; c_gesture* m_gesture; }; //#define SWIPE_STEP 300//for arm #define SWIPE_STEP 10//for PC & ANDROID #define MOVE_THRESHOLD 10 typedef enum { TOUCH_MOVE, TOUCH_IDLE }TOUCH_STATE; class c_slide_group; class c_gesture { public: c_gesture(c_slide_group* group) { m_slide_group = group; m_state = TOUCH_IDLE; m_down_x = m_down_y = m_move_x = m_move_y = 0; } bool handle_swipe(int x, int y, TOUCH_ACTION action) { if (action == TOUCH_DOWN)//MOUSE_LBUTTONDOWN { if (m_state == TOUCH_IDLE) { m_state = TOUCH_MOVE; m_move_x = m_down_x = x; return true; } else//TOUCH_MOVE { return on_move(x); } } else if (action == TOUCH_UP)//MOUSE_LBUTTONUP { if (m_state == TOUCH_MOVE) { m_state = TOUCH_IDLE; return on_swipe(x); } else { return false; //ASSERT(false); } } return true; } private: bool on_move(int x) { if (m_slide_group == 0) { return true; } if (abs(x - m_move_x) < MOVE_THRESHOLD) { return false; } m_slide_group->disabel_all_slide(); m_move_x = x; if ((m_move_x - m_down_x) > 0) { move_right(); } else { move_left(); } return false; } bool on_swipe(int x) { if (m_slide_group == 0) { return true; } if ((m_down_x == m_move_x) && (abs(x - m_down_x) < MOVE_THRESHOLD)) { return true; } m_slide_group->disabel_all_slide(); int page = -1; m_move_x = x; if ((m_move_x - m_down_x) > 0) { page = swipe_right(); } else { page = swipe_left(); } if (page >= 0) { m_slide_group->set_active_slide(page); } else { m_slide_group->set_active_slide(m_slide_group->get_active_slide_index(), false); } return false; } int swipe_left() { if (m_slide_group == 0) { return -1; } int index = m_slide_group->get_active_slide_index(); if ((index + 1) >= MAX_PAGES || m_slide_group->get_slide(index + 1) == 0 || m_slide_group->get_slide(index) == 0) { return -2; } c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); if (s1->get_display() != s2->get_display()) { return -3; } int step = m_down_x - m_move_x; c_rect rc; m_slide_group->get_screen_rect(rc); while (step < rc.width()) { s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); step += SWIPE_STEP; } if (step != rc.width()) { s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, rc.width()); } return (index + 1); } int swipe_right() { if (m_slide_group == 0) { return -1; } int index = m_slide_group->get_active_slide_index(); if (index <= 0 || m_slide_group->get_slide(index - 1) == 0 || m_slide_group->get_slide(index) == 0) { return -2; } c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); if (s1->get_display() != s2->get_display()) { return -3; } c_rect rc; m_slide_group->get_screen_rect(rc); int step = rc.width() - (m_move_x - m_down_x); while (step > 0) { s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); step -= SWIPE_STEP; } if (step != 0) { s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, 0); } return (index - 1); } void move_left() { int index = m_slide_group->get_active_slide_index(); if ((index + 1) >= MAX_PAGES || m_slide_group->get_slide(index + 1) == 0 || m_slide_group->get_slide(index) == 0) { return; } c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); c_rect rc; m_slide_group->get_screen_rect(rc); if (s1->get_display() == s2->get_display()) { s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (m_down_x - m_move_x)); } } void move_right() { int index = m_slide_group->get_active_slide_index(); if (index <= 0 || m_slide_group->get_slide(index - 1) == 0 || m_slide_group->get_slide(index) == 0) { return; } c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); c_rect rc; m_slide_group->get_screen_rect(rc); if (s1->get_display() == s2->get_display()) { s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (rc.width() - (m_move_x - m_down_x))); } } int m_down_x; int m_down_y; int m_move_x; int m_move_y; TOUCH_STATE m_state; c_slide_group* m_slide_group; }; inline c_slide_group::c_slide_group() { m_gesture = new c_gesture(this); for (int i = 0; i < MAX_PAGES; i++) { m_slides[i] = 0; } m_active_slide_index = 0; } inline void c_slide_group::on_touch(int x, int y, TOUCH_ACTION action) { x -= m_wnd_rect.m_left; y -= m_wnd_rect.m_top; if (m_gesture->handle_swipe(x, y, action)) { if (m_slides[m_active_slide_index]) { m_slides[m_active_slide_index]->on_touch(x, y, action); } } } ================================================ FILE: src/widgets/spinbox.h ================================================ #pragma once #include "../core/api.h" #include "../core/wnd.h" #include "../core/resource.h" #include "../core/word.h" #include "../core/display.h" #include "../core/theme.h" #include "../widgets/button.h" #define ID_BT_ARROW_UP 0x1111 #define ID_BT_ARROW_DOWN 0x2222 class c_spin_box; class c_spin_button : public c_button { friend class c_spin_box; inline virtual void on_touch(int x, int y, TOUCH_ACTION action); c_spin_box* m_spin_box; }; class c_spin_box : public c_wnd { friend class c_spin_button; public: short get_value() { return m_value; } void set_value(unsigned short value) { m_value = m_cur_value = value; } void set_max_min(short max, short min) { m_max = max; m_min = min; } void set_step(short step) { m_step = step; } short get_min() { return m_min; } short get_max() { return m_max; } short get_step() { return m_step; } void set_value_digit(short digit) { m_digit = digit; } short get_value_digit() { return m_digit; } void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } protected: virtual void on_paint() { c_rect rect; get_screen_rect(rect); rect.m_right = rect.m_left + (rect.width() * 2 / 3); m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); c_word::draw_value_in_rect(m_surface, m_parent->get_z_order(), m_cur_value, m_digit, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); } virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); m_max = 6; m_min = 1; m_digit = 0; m_step = 1; //link arrow button position. c_rect rect; get_wnd_rect(rect); m_bt_down.m_spin_box = m_bt_up.m_spin_box = this; m_bt_up.connect(m_parent, ID_BT_ARROW_UP, "+", (rect.m_left + rect.width() * 2 / 3), rect.m_top, (rect.width() / 3), (rect.height() / 2)); m_bt_down.connect(m_parent, ID_BT_ARROW_DOWN, "-", (rect.m_left + rect.width() * 2 / 3), (rect.m_top + rect.height() / 2), (rect.width() / 3), (rect.height() / 2)); } void on_arrow_up_bt_click() { if (m_cur_value + m_step > m_max) { return; } m_cur_value += m_step; if(on_change) { (m_parent->*(on_change))(m_id, m_cur_value); } on_paint(); } void on_arrow_down_bt_click() { if (m_cur_value - m_step < m_min) { return; } m_cur_value -= m_step; if(on_change) { (m_parent->*(on_change))(m_id, m_cur_value); } on_paint(); } short m_cur_value; short m_value; short m_step; short m_max; short m_min; short m_digit; c_spin_button m_bt_up; c_spin_button m_bt_down; WND_CALLBACK on_change; }; inline void c_spin_button::on_touch(int x, int y, TOUCH_ACTION action) { if (action == TOUCH_UP) { (m_id == ID_BT_ARROW_UP) ? m_spin_box->on_arrow_up_bt_click() : m_spin_box->on_arrow_down_bt_click(); } c_button::on_touch(x, y, action); } ================================================ FILE: src/widgets/table.h ================================================ #pragma once #include "../core/api.h" #include "../core/resource.h" #include "../core/word.h" #include "../core/display.h" #include "../core/theme.h" #include "../core/wnd.h" #define MAX_COL_NUM 30 #define MAX_ROW_NUM 30 class c_table: public c_wnd { public: void set_sheet_align(unsigned int align_type){ m_align_type = align_type;} void set_row_num(unsigned int row_num){ m_row_num = row_num;} void set_col_num(unsigned int col_num){ m_col_num = col_num;} void set_row_height(unsigned int height) { for (unsigned int i = 0; i < m_row_num; i++) { m_row_height[i] = height; } } void set_col_width(unsigned int width) { for (unsigned int i = 0; i < m_col_num; i++) { m_col_width[i] = width; } } int set_row_height(unsigned int index, unsigned int height) { if (m_row_num > index) { m_row_height[index] = height; return index; } return -1; } int set_col_width(unsigned int index, unsigned int width) { if (m_col_num > index) { m_col_width[index] = width; return index; } return -1; } void set_item(int row, int col, char* str, unsigned int color) { draw_item(row, col, str, color); } unsigned int get_row_num(){ return m_row_num;} unsigned int get_col_num(){ return m_col_num;} c_rect get_item_rect(int row, int col) { static c_rect rect; if (row >= MAX_ROW_NUM || col >= MAX_COL_NUM) { return rect; } unsigned int width = 0; unsigned int height = 0; for (int i = 0; i < col; i++) { width += m_col_width[i]; } for (int j = 0; j < row; j++) { height += m_row_height[j]; } c_rect wRect; get_screen_rect(wRect); rect.m_left = wRect.m_left + width; rect.m_right = rect.m_left + m_col_width[col]; if (rect.m_right > wRect.m_right) { rect.m_right = wRect.m_right; } rect.m_top = wRect.m_top + height; rect.m_bottom = rect.m_top + m_row_height[row]; if (rect.m_bottom > wRect.m_bottom) { rect.m_bottom = wRect.m_bottom; } return rect; } protected: virtual void pre_create_wnd() { m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); m_font = c_theme::get_font(FONT_DEFAULT); m_font_color = c_theme::get_color(COLOR_WND_FONT); } void draw_item(int row, int col, const char* str, unsigned int color) { c_rect rect = get_item_rect(row, col); m_surface->fill_rect(rect.m_left + 1, rect.m_top + 1, rect.m_right - 1, rect.m_bottom - 1, color, m_z_order); c_word::draw_string_in_rect(m_surface, m_z_order, str, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_align_type); } unsigned int m_align_type; unsigned int m_row_num; unsigned int m_col_num; unsigned int m_row_height[MAX_ROW_NUM]; unsigned int m_col_width[MAX_COL_NUM]; }; ================================================ FILE: src/widgets/wave_buffer.h ================================================ #pragma once #include "../core/api.h" #include #include #define WAVE_BUFFER_LEN 1024 #define WAVE_READ_CACHE_LEN 8 #define BUFFER_EMPTY -1111 #define BUFFER_FULL -2222; class c_wave_buffer { public: c_wave_buffer() { m_head = m_tail = m_min_old = m_max_old = m_min_older = m_max_older = m_last_data = m_read_cache_sum = m_refresh_sequence = 0; memset(m_wave_buf, 0, sizeof(m_wave_buf)); memset(m_read_cache_min, 0, sizeof(m_read_cache_min)); memset(m_read_cache_mid, 0, sizeof(m_read_cache_mid)); memset(m_read_cache_max, 0, sizeof(m_read_cache_max)); } int write_wave_data(short data) { if ((m_tail + 1) % WAVE_BUFFER_LEN == m_head) {//full //log_out("wave buf full\n"); return BUFFER_FULL; } m_wave_buf[m_tail] = data; m_tail = (m_tail + 1) % WAVE_BUFFER_LEN; return 1; } int read_wave_data_by_frame(short &max, short &min, short frame_len, unsigned int sequence, short offset) { if (m_refresh_sequence != sequence) { m_refresh_sequence = sequence; m_read_cache_sum = 0; } else if (offset < m_read_cache_sum)//(m_refresh_sequence == sequence && offset < m_fb_sum) { max = m_read_cache_max[offset]; min = m_read_cache_min[offset]; return m_read_cache_mid[offset]; } m_read_cache_sum++; ASSERT(m_read_cache_sum <= WAVE_READ_CACHE_LEN); int i, data; int tmp_min = m_last_data; int tmp_max = m_last_data; int mid = (m_min_old + m_max_old) >> 1; i = 0; while (i++ < frame_len) { data = read_data(); if (BUFFER_EMPTY == data) { break; } m_last_data = data; if (data < tmp_min) { tmp_min = data; } if (data > tmp_max) { tmp_max = data; } } min = m_read_cache_min[offset] = MIN(m_min_old, MIN(tmp_min, m_min_older)); max = m_read_cache_max[offset] = MAX(m_max_old, MAX(tmp_max, m_max_older)); m_min_older = m_min_old; m_max_older = m_max_old; m_min_old = tmp_min; m_max_old = tmp_max; return (m_read_cache_mid[offset] = mid); } void reset() { m_head = m_tail; } void clear_data() { m_head = m_tail = 0; memset(m_wave_buf, 0, sizeof(m_wave_buf)); } short get_cnt() { return (m_tail >= m_head) ? (m_tail - m_head) : (m_tail - m_head + WAVE_BUFFER_LEN); } private: int read_data() { if (m_head == m_tail) {//empty //log_out("wave buf empty\n"); return BUFFER_EMPTY; } int ret = m_wave_buf[m_head]; m_head = (m_head + 1) % WAVE_BUFFER_LEN; return ret; } short m_wave_buf[WAVE_BUFFER_LEN]; short m_head; short m_tail; int m_min_old; int m_max_old; int m_min_older; int m_max_older; int m_last_data; short m_read_cache_min[WAVE_READ_CACHE_LEN]; short m_read_cache_mid[WAVE_READ_CACHE_LEN]; short m_read_cache_max[WAVE_READ_CACHE_LEN]; short m_read_cache_sum; unsigned int m_refresh_sequence; }; ================================================ FILE: src/widgets/wave_ctrl.h ================================================ #pragma once #include "../core/api.h" #include "../core/wnd.h" #include "../core/display.h" #include "../core/resource.h" #include "../core/word.h" #include "../widgets/wave_buffer.h" #include #include #define CORRECT(x, high_limit, low_limit) {\ x = (x > high_limit) ? high_limit : x;\ x = (x < low_limit) ? low_limit : x;\ }while(0) #define WAVE_CURSOR_WIDTH 8 #define WAVE_LINE_WIDTH 1 #define WAVE_MARGIN 5 typedef enum { FILL_MODE, SCAN_MODE }E_WAVE_DRAW_MODE; class c_wave_buffer; class c_wave_ctrl : public c_wnd { public: c_wave_ctrl() { m_wave = 0; m_bg_fb = 0; m_wave_name_font = m_wave_unit_font = 0; m_wave_name = m_wave_unit = 0; m_max_data = 500; m_min_data = 0; m_wave_speed = 1; m_wave_data_rate = 0; m_wave_refresh_rate = 1000; m_frame_len_map_index = 0; m_wave_name_color = m_wave_unit_color = m_wave_color = GL_RGB(255, 0, 0); m_back_color = GL_RGB(0, 0, 0); } virtual void on_init_children()//should be pre_create { c_rect rect; get_screen_rect(rect); m_wave_left = rect.m_left + WAVE_MARGIN; m_wave_right = rect.m_right - WAVE_MARGIN; m_wave_top = rect.m_top + WAVE_MARGIN; m_wave_bottom = rect.m_bottom - WAVE_MARGIN; m_wave_cursor = m_wave_left; m_bg_fb = (unsigned int*)calloc(rect.width() * rect.height(), 4); } virtual void on_paint() { c_rect rect; get_screen_rect(rect); m_surface->fill_rect(rect, m_back_color, m_z_order); //show name c_word::draw_string(m_surface, m_z_order, m_wave_name, m_wave_left + 10, rect.m_top, m_wave_name_font, m_wave_name_color, GL_ARGB(0, 0, 0, 0)); //show unit c_word::draw_string(m_surface, m_z_order, m_wave_unit, m_wave_left + 60, rect.m_top, m_wave_unit_font, m_wave_unit_color, GL_ARGB(0, 0, 0, 0)); save_background(); } void set_wave_name(char* wave_name){ m_wave_name = wave_name;} void set_wave_unit(char* wave_unit){ m_wave_unit = wave_unit;} void set_wave_name_font(const LATTICE_FONT_INFO* wave_name_font_type){ m_wave_name_font = wave_name_font_type;} void set_wave_unit_font(const LATTICE_FONT_INFO* wave_unit_font_type){ m_wave_unit_font = wave_unit_font_type;} void set_wave_name_color(unsigned int wave_name_color){ m_wave_name_color = wave_name_color;} void set_wave_unit_color(unsigned int wave_unit_color){ m_wave_unit_color = wave_unit_color;} void set_wave_color(unsigned int color){ m_wave_color = color;} void set_wave_in_out_rate(unsigned int data_rate, unsigned int refresh_rate) { m_wave_data_rate = data_rate; m_wave_refresh_rate = refresh_rate; int read_times_per_second = m_wave_speed * 1000 / m_wave_refresh_rate; memset(m_frame_len_map, 0, sizeof(m_frame_len_map)); for (unsigned int i = 1; i < sizeof(m_frame_len_map) + 1; i++) { m_frame_len_map[i - 1] = data_rate * i / read_times_per_second - data_rate * (i - 1) / read_times_per_second; } m_frame_len_map_index = 0; } void set_wave_speed(unsigned int speed) { m_wave_speed = speed; set_wave_in_out_rate(m_wave_data_rate, m_wave_refresh_rate); } void set_max_min(short max_data, short min_data) { m_max_data = max_data; m_min_data = min_data; } void set_wave(c_wave_buffer* wave){m_wave = wave;} c_wave_buffer* get_wave(){return m_wave;} void clear_data() { if (m_wave == 0) { ASSERT(false); return; } m_wave->clear_data(); } bool is_data_enough() { if (m_wave == 0) { ASSERT(false); return false; } return (m_wave->get_cnt() - m_frame_len_map[m_frame_len_map_index] * m_wave_speed); } void refresh_wave(unsigned char frame) { if (m_wave == 0) { ASSERT(false); return; } short max, min, mid; for (short offset = 0; offset < m_wave_speed; offset++) { //get wave value mid = m_wave->read_wave_data_by_frame(max, min, m_frame_len_map[m_frame_len_map_index++], frame, offset); m_frame_len_map_index %= sizeof(m_frame_len_map); //map to wave ctrl int y_min, y_max; if (m_max_data == m_min_data) { ASSERT(false); } y_max = m_wave_bottom + WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (min - m_min_data) / (m_max_data - m_min_data); y_min = m_wave_bottom - WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (max - m_min_data) / (m_max_data - m_min_data); mid = m_wave_bottom - (m_wave_bottom - m_wave_top) * (mid - m_min_data) / (m_max_data - m_min_data); CORRECT(y_min, m_wave_bottom, m_wave_top); CORRECT(y_max, m_wave_bottom, m_wave_top); CORRECT(mid, m_wave_bottom, m_wave_top); if (m_wave_cursor > m_wave_right) { m_wave_cursor = m_wave_left; } draw_smooth_vline(y_min, y_max, mid, m_wave_color); restore_background(); m_wave_cursor++; } } void clear_wave() { m_surface->fill_rect(m_wave_left, m_wave_top, m_wave_right, m_wave_bottom, m_back_color, m_z_order); m_wave_cursor = m_wave_left; } protected: void draw_smooth_vline(int y_min, int y_max, int mid, unsigned int rgb) { int dy = y_max - y_min; short r = GL_RGB_R(rgb); short g = GL_RGB_G(rgb); short b = GL_RGB_B(rgb); int index = (dy >> 1) + 2; int y; m_surface->draw_pixel(m_wave_cursor, mid, rgb, m_z_order); if (dy < 1) { return; } unsigned char cur_r, cur_g, cur_b; unsigned int cur_rgb; for (int i = 1; i <= (dy >> 1) + 1; ++i) { if ((mid + i) <= y_max) { y = mid + i; cur_r = r * (index - i) / index; cur_g = g * (index - i) / index; cur_b = b * (index - i) / index; cur_rgb = GL_RGB(cur_r, cur_g, cur_b); m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); } if ((mid - i) >= y_min) { y = mid - i; cur_r = r * (index - i) / index; cur_g = g * (index - i) / index; cur_b = b * (index - i) / index; cur_rgb = GL_RGB(cur_r, cur_g, cur_b); m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); } } } void restore_background() { int x = m_wave_cursor + WAVE_CURSOR_WIDTH; if (x > m_wave_right) { x -= (m_wave_right - m_wave_left + 1); } c_rect rect; get_screen_rect(rect); int width = rect.width(); int top = rect.m_top; int left = rect.m_left; for (int y_pos = (m_wave_top - 1); y_pos <= (m_wave_bottom + 1); y_pos++) { (m_bg_fb) ? m_surface->draw_pixel(x, y_pos, m_bg_fb[(y_pos - top) * width + (x - left)], m_z_order) : m_surface->draw_pixel(x, y_pos, 0, m_z_order); } } void save_background() { if (!m_bg_fb) { return; } c_rect rect; get_screen_rect(rect); unsigned int* p_des = m_bg_fb; for (int y = rect.m_top; y <= rect.m_bottom; y++) { for (int x = rect.m_left; x <= rect.m_right; x++) { *p_des++ = m_surface->get_pixel(x, y, m_z_order); } } } char* m_wave_name; char* m_wave_unit; const LATTICE_FONT_INFO* m_wave_name_font; const LATTICE_FONT_INFO* m_wave_unit_font; unsigned int m_wave_name_color; unsigned int m_wave_unit_color; unsigned int m_wave_color; unsigned int m_back_color; int m_wave_left; int m_wave_right; int m_wave_top; int m_wave_bottom; short m_max_data; short m_min_data; private: c_wave_buffer* m_wave; unsigned int* m_bg_fb; //background frame buffer, could be used to draw scale line. int m_wave_cursor; int m_wave_speed; //pixels per refresh unsigned int m_wave_data_rate; //data sample rate unsigned int m_wave_refresh_rate;//refresh cycle in millisecond unsigned char m_frame_len_map[64]; unsigned char m_frame_len_map_index; }; ================================================ FILE: src/widgets/widgets.cpp ================================================ #include "../widgets/button.h" #include "../widgets/dialog.h" #include "../widgets/keyboard.h" #include "../widgets/label.h" #include "../widgets/list_box.h" #include "../widgets/slide_group.h" #include "../widgets/spinbox.h" #include "../widgets/table.h" #include "../widgets/wave_buffer.h" #include "../widgets/wave_ctrl.h" #include "../widgets/edit.h" #ifdef GUILITE_ON DIALOG_ARRAY c_dialog::ms_the_dialogs[SURFACE_CNT_MAX]; c_keyboard c_edit::s_keyboard; static c_keyboard_button s_key_0, s_key_1, s_key_2, s_key_3, s_key_4, s_key_5, s_key_6, s_key_7, s_key_8, s_key_9; static c_keyboard_button s_key_A, s_key_B, s_key_C, s_key_D, s_key_E, s_key_F, s_key_G, s_key_H, s_key_I, s_key_J; static c_keyboard_button s_key_K, s_key_L, s_key_M, s_key_N, s_key_O, s_key_P, s_key_Q, s_key_R, s_key_S, s_key_T; static c_keyboard_button s_key_U, s_key_V, s_key_W, s_key_X, s_key_Y, s_key_Z; static c_keyboard_button s_key_dot, s_key_caps, s_key_space, s_key_enter, s_key_del, s_key_esc, s_key_num_switch; WND_TREE g_key_board_children[] = { //Row 1 {&s_key_Q, 'Q', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_W, 'W', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_E, 'E', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_R, 'R', 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_T, 'T', 0, POS_X(4), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_Y, 'Y', 0, POS_X(5), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_U, 'U', 0, POS_X(6), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_I, 'I', 0, POS_X(7), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_O, 'O', 0, POS_X(8), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_P, 'P', 0, POS_X(9), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, //Row 2 {&s_key_A, 'A', 0, ((KEY_WIDTH / 2) + POS_X(0)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_S, 'S', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_D, 'D', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_F, 'F', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_G, 'G', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_H, 'H', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_J, 'J', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_K, 'K', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_L, 'L', 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, //Row 3 {&s_key_caps, 0x14, 0, POS_X(0), POS_Y(2), CAPS_WIDTH, KEY_HEIGHT}, {&s_key_Z, 'Z', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_X, 'X', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_C, 'C', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_V, 'V', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_B, 'B', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_N, 'N', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_M, 'M', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_del,0x7F, 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(2), DEL_WIDTH, KEY_HEIGHT}, //Row 4 {&s_key_esc, 0x1B, 0, POS_X(0), POS_Y(3), ESC_WIDTH, KEY_HEIGHT}, {&s_key_num_switch, 0x90, 0, POS_X(2), POS_Y(3), SWITCH_WIDTH, KEY_HEIGHT}, {&s_key_space, ' ', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(3), SPACE_WIDTH, KEY_HEIGHT}, {&s_key_dot, '.', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(3), DOT_WIDTH, KEY_HEIGHT}, {&s_key_enter, '\n', 0, POS_X(8), POS_Y(3), ENTER_WIDTH, KEY_HEIGHT}, {0,0,0,0,0,0,0} }; WND_TREE g_number_board_children[] = { {&s_key_1, '1', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_2, '2', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_3, '3', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, {&s_key_4, '4', 0, POS_X(0), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_5, '5', 0, POS_X(1), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_6, '6', 0, POS_X(2), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, {&s_key_7, '7', 0, POS_X(0), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_8, '8', 0, POS_X(1), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_9, '9', 0, POS_X(2), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, {&s_key_esc,0x1B, 0, POS_X(0), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, {&s_key_0, '0', 0, POS_X(1), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, {&s_key_dot,'.', 0, POS_X(2), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, {&s_key_del, 0x7F, 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, {&s_key_enter,'\n', 0, POS_X(3), POS_Y(2), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, {0,0,0,0,0,0,0} }; #endif

開發群🔑:875721211