GuiLite开源GUI学习(一):display与surface类 您所在的位置:网站首页 surfacedisplay GuiLite开源GUI学习(一):display与surface类

GuiLite开源GUI学习(一):display与surface类

2023-05-24 01:58| 来源: 网络整理| 查看: 265

GuiLite开源GUI学习(一) 移植相关文件display类surface类画图时`z_order`的意义 surface和display及c_layer的关系疑问 GuiLite项目地址

移植相关文件

UICode.cpp:逻辑代码的编写,向外提供一个接口,如startHello3Ddonut。

static c_surface* s_surface; static c_display* s_display; // Demo void create_ui(void* phy_fb, int screen_width, int screen_height, int color_bytes, struct EXTERNAL_GFX_OP* gfx_op) { if (phy_fb) { static c_surface surface(UI_WIDTH, UI_HEIGHT, color_bytes, Z_ORDER_LEVEL_0); static c_display display(phy_fb, screen_width, screen_height, &surface); s_surface = &surface; s_display = &display; } else {//for MCU without framebuffer static c_surface_no_fb surface_no_fb(UI_WIDTH, UI_HEIGHT, color_bytes, gfx_op, Z_ORDER_LEVEL_0); static c_display display(phy_fb, screen_width, screen_height, &surface_no_fb); s_surface = &surface_no_fb; s_display = &display; } s_surface->fill_rect(0, 0, UI_WIDTH - 1, UI_HEIGHT - 1, 0, Z_ORDER_LEVEL_0); // 向主题添加一个字体,改字体的标识为FONT_DEFAULT,后面可以根据这个标识取出。 c_theme::add_font(FONT_DEFAULT, &Consolas_13); while(true) { build_frame(); render_frame(); } } interface for all platform // main.c中调用此接口 extern "C" void startHello3Ddonut(void* phy_fb, int width, int height, int color_bytes, struct EXTERNAL_GFX_OP* gfx_op) { create_ui(phy_fb, width, height, color_bytes, gfx_op); }

main.c:负责画点函数draw_pixel的移植

//Transfer GuiLite 32 bits color to your LCD color #define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8)) //Encapsulate your LCD driver: void gfx_draw_pixel(int x, int y, unsigned int rgb) { LCD_Draw_ColorPoint(x, y, GL_RGB_32_to_16(rgb)); } //Implement it, if you have more fast solution than drawing pixels one by one. void gfx_fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) { LCD_Fill(x0, y0, x1, y1, GL_RGB_32_to_16(rgb)); } //UI entry struct EXTERNAL_GFX_OP { void (*draw_pixel)(int x, int y, unsigned int rgb); void (*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb); } my_gfx_op; extern void startHello3Ddonut(void* phy_fb, int width, int height, int color_bytes, struct EXTERNAL_GFX_OP* gfx_op); int mian() { ...... // 画点函数的移植 my_gfx_op.draw_pixel = gfx_draw_pixel; my_gfx_op.fill_rect = gfx_fill_rect;//gfx_fill_rect; startHello3Ddonut(NULL, 240, 240, 2, &my_gfx_op); }

注意点:

static c_surface_no_fb surface_no_fb(UI_WIDTH, UI_HEIGHT, color_bytes, gfx_op, Z_ORDER_LEVEL_0); // 虽然画图时都是通过surface,但是下面这句话不能注释掉,因为下面这句话会对surface_no_fb进行赋值,不然的话surface_no_fb是无效值。 static c_display display(phy_fb, screen_width, screen_height, &surface_no_fb); // 因为: inline c_display::c_display(..., c_surface* surface) { m_color_bytes = surface->m_color_bytes; // 这句话设置surface为有效的 surface->m_is_active = true; (m_surface_group[0] = surface)->attach_display(this); } s_surface = &surface_no_fb; // 这句话可以注释掉 s_display = &display;

注意: 使用时只需包含头文件GuiLite.h,此头文件中包含一些已实现的控件。在GuiLite项目中,作者也将各个模块抽离出来,方便读者研究,即GuiLite的src目录下。

display类

surface是它的友元类,即surface可以访问display的属性和方法。

属性:

void* m_phy_fb; //physical framebuffer int m_phy_read_index; int m_phy_write_index; c_surface* m_surface_group[SURFACE_CNT_MAX]; ///对应多个surface int m_surface_cnt; //surface count int m_surface_index;

注意点:

一个display只有一个m_phy_fb;但是有SURFACE_CNT_MAX个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, EXTERNAL_GFX_OP* gfx_op = 0);// 创建拥有surface_cnt个surface的display inline c_display(void* phy_fb, int display_width, int display_height, c_surface* surface);// 创建单层surface的display,且为fb模式 inline c_surface* alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect = c_rect());//为display申请多个surface inline int swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset); // 得到最新的fb void* get_updated_fb(int* width, int* height, bool force_update = false); // 将当前的fb保存到文件(bmp形式) int snap_shot(const char* file_name) surface类

display和bitmap都是surface的友元类。

方法:

// 构造函数只有一个 void c_surface(, 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_fb(0), m_phy_write_index(0), m_display(0); // 此函数是将m_fb的值刷新到m_phy_fb。 void flush_screen(x1, y1, x2, y2);

surface分为带有framebuffer和不带framebuffer的surface,两者的区别不大,只是不带fb的多了一个struct EXTERNAL_GFX_OP* m_gfx_op属性,主要原因是:

带有framebuffer的可以直接对某块内存进行对写;不带有framebuffer的surface通过m_gfx_op中的draw_pixel来重写virtual void draw_pixel_on_fb(int x, int y, unsigned int rgb);通过上述可知,最终两种surface在使用上没有区别。

属性:

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; //surface拥有的最多layer个数 Z_ORDER_LEVEL m_top_zorder; //指向你当前想显示的layer void* m_phy_fb; //physical framebufer int* m_phy_write_index; c_display* m_display; // 没有fb的还要多个struct EXTERNAL_GFX_OP* m_gfx_op成员

注意点:

一个surface指向一个display,也指向一个m_fb和m_phy_fb;有多个layer;即一个display指向多个surface、一个surface有多个layer;

方法:

// 有很多不同的画图方法,调用的都是 virtual void draw_pixel(int x, int y, unsigned int rgb, unsigned int z_order); // 但最终是调用的是(没有fb的会被重写,通过m_gfx_op属性): draw_pixel_on_fb(x, y, rgb); 画图时z_order的意义

draw_pixel(x, y, rgb, z_order)的意义(非常重要!!!):

一个surface有多层layer,有两个属性z_max_order(surface最多拥有的layer个数)和z_top_order(当前surface的最顶层)。而其作用就是:

判断点(x,y)是否在m_layers[z_order].rect中,如果在,那么就将m_layers[z_order].fb更新;然后判断z_order是否在最大层z_max_order,如果在,则将其立刻显示到屏幕上去;如果z_order>m_top_order,则m_top_order=z_order,即更新最顶层;如果z_order=m_top_order,也立即将其显示到屏幕上去;走到这里,说明z_ordertop else 立即显示 需调用show_layer(,zorder) 只是对m_layer[z_order]赋值 draw_pixel(,z_order) draw_line draw_rect fill_rect draw_pixel_on_fb(,z_order) z_order gfx.draw_pixe(x,y,rgb) m_layers[m_top_zorder] m_max_zorder m_top_zorder(value=0:max-1) top=z_order surface和display及c_layer的关系 一个display指向多个surface,指向一个fb;每个surface都指向一个fb,也指向一个display;每个surface有多个layer,用z_order标识;一个layer其实就是一个c_rect,然后还指向了一个fb,注意这个fb不是物理的,而是一个内存,即每个layer的fb都不同;surface的show_layer(c_rect& rect, z_order)就是展示第z_order个layer,但是注意,c_rect必须在m_layers[z_order].rect之中;&是C++中的引用,用作函数参数时,效果同指针。它会从fb中读取rgb值,然后再调用draw_pixel_on_fb(x,y,rgb)。 疑问

在创建display时创建了多个surface,怎么获取想要的surface?此问终于解了

在阅读slide_group.h和HelloSlide.h源码时,终于发现怎么获取想要的surface。display的部分属性如下:

c_surface* m_surface_group[SURFACE_CNT_MAX]; int m_surface_cnt; //在创建时传入 int m_surface_index; c_surface* alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect);

m_surface_index用于索引对应的surface,我发现其只在alloc_surface中会被改变,然后又看了slide_group.h源码:

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) { 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); }

先通过第一个surface获取display,然后再调用alloc_surface(),这个会返回新的surface。

画图时,都是通过surface的,那么display有什么用?

未完待续…



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有