/** * @file win_drv.c * */ /********************* * INCLUDES *********************/ #include "win_drv.h" #if USE_WINDOWS #include #include #include "lvgl/lvgl.h" #if LV_COLOR_DEPTH < 16 #error Windows driver only supports true RGB colors at this time #endif /********************** * DEFINES **********************/ #define WINDOW_STYLE (WS_OVERLAPPEDWINDOW & ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME)) /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ static void do_register(void); static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p); static void win_drv_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); static void win_drv_read(lv_indev_t *drv, lv_indev_data_t * data); static void msg_handler(void *param); static COLORREF lv_color_to_colorref(const lv_color_t color); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); /********************** * GLOBAL VARIABLES **********************/ bool lv_win_exit_flag = false; lv_disp_t *lv_windows_disp; /********************** * STATIC VARIABLES **********************/ static HWND hwnd; static uint32_t *fbp = NULL; /* Raw framebuffer memory */ static bool mouse_pressed; static int mouse_x, mouse_y; /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ const char g_szClassName[] = "LVGL"; HWND windrv_init(void) { WNDCLASSEX wc; RECT winrect; HICON lvgl_icon; //Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(NULL); lvgl_icon = (HICON) LoadImage( NULL, "lvgl_icon.bmp", IMAGE_ICON, 0, 0, LR_LOADFROMFILE); if(lvgl_icon == NULL) lvgl_icon = LoadIcon(NULL, IDI_APPLICATION); wc.hIcon = lvgl_icon; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = lvgl_icon; if(!RegisterClassEx(&wc)) { return NULL; } winrect.left = 0; winrect.right = WINDOW_HOR_RES - 1; winrect.top = 0; winrect.bottom = WINDOW_VER_RES - 1; AdjustWindowRectEx(&winrect, WINDOW_STYLE, FALSE, WS_EX_CLIENTEDGE); OffsetRect(&winrect, -winrect.left, -winrect.top); // Step 2: Creating the Window hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, "LVGL Simulator", WINDOW_STYLE, CW_USEDEFAULT, CW_USEDEFAULT, winrect.right, winrect.bottom, NULL, NULL, GetModuleHandle(NULL), NULL); if(hwnd == NULL) { return NULL; } ShowWindow(hwnd, SW_SHOWDEFAULT); UpdateWindow(hwnd); lv_task_create(msg_handler, 0, LV_TASK_PRIO_HIGHEST, NULL); lv_win_exit_flag = false; do_register(); } /********************** * STATIC FUNCTIONS **********************/ static void do_register(void) { static lv_disp_draw_buf_t disp_buf_1; static lv_color_t buf1_1[WINDOW_HOR_RES * 100]; /*A buffer for 10 rows*/ lv_disp_draw_buf_init(&disp_draw_buf_1, buf1_1, NULL, WINDOW_HOR_RES * 100); /*Initialize the display buffer*/ /*----------------------------------- * Register the display in LVGLGL *----------------------------------*/ static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv); /*Basic initialization*/ /*Set up the functions to access to your display*/ /*Set the resolution of the display*/ disp_drv.hor_res = WINDOW_HOR_RES; disp_drv.ver_res = WINDOW_VER_RES; /*Used to copy the buffer's content to the display*/ disp_drv.flush_cb = win_drv_flush; /*Set a display buffer*/ disp_drv.draw_buf = &disp_buf_1; /*Finally register the driver*/ lv_windows_disp = lv_disp_drv_register(&disp_drv); static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = win_drv_read; lv_indev_drv_register(&indev_drv); } static void msg_handler(void *param) { (void)param; MSG msg; BOOL bRet; if( (bRet = PeekMessage( &msg, NULL, 0, 0, TRUE )) != 0) { if (bRet == -1) { return; } else { TranslateMessage(&msg); DispatchMessage(&msg); } if(msg.message == WM_QUIT) lv_win_exit_flag = true; } } static void win_drv_read(lv_indev_t *drv, lv_indev_data_t * data) { data->state = mouse_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; data->point.x = mouse_x; data->point.y = mouse_y; } static void on_paint(void) { HBITMAP bmp = CreateBitmap(WINDOW_HOR_RES, WINDOW_VER_RES, 1, 32, fbp); PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hbmOld = SelectObject(hdcMem, bmp); BitBlt(hdc, 0, 0, WINDOW_HOR_RES, WINDOW_VER_RES, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, hbmOld); DeleteDC(hdcMem); EndPaint(hwnd, &ps); DeleteObject(bmp); } /** * Flush a buffer to the marked area * @param x1 left coordinate * @param y1 top coordinate * @param x2 right coordinate * @param y2 bottom coordinate * @param color_p an array of colors */ static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p) { win_drv_map(area->x1, area->y1, area->x2, area->y2, color_p); lv_disp_flush_ready(drv); } /** * Put a color map to the marked area * @param x1 left coordinate * @param y1 top coordinate * @param x2 right coordinate * @param y2 bottom coordinate * @param color_p an array of colors */ static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) { for(int y = y1; y <= y2; y++) { for(int x = x1; x <= x2; x++) { fbp[y*WINDOW_HOR_RES+x] = lv_color_to32(*color_p); color_p++; } } InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch(msg) { case WM_CREATE: fbp = malloc(4*WINDOW_HOR_RES*WINDOW_VER_RES); if(fbp == NULL) return 1; SetTimer(hwnd, 0, 10, (TIMERPROC)lv_task_handler); SetTimer(hwnd, 1, 25, NULL); return 0; case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: mouse_x = GET_X_LPARAM(lParam); mouse_y = GET_Y_LPARAM(lParam); if(msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { mouse_pressed = (msg == WM_LBUTTONDOWN); } return 0; case WM_CLOSE: free(fbp); fbp = NULL; DestroyWindow(hwnd); return 0; case WM_PAINT: on_paint(); return 0; case WM_TIMER: lv_tick_inc(25); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); } static COLORREF lv_color_to_colorref(const lv_color_t color) { uint32_t raw_color = lv_color_to32(color); lv_color32_t tmp; tmp.full = raw_color; uint32_t colorref = RGB(tmp.ch.red, tmp.ch.green, tmp.ch.blue); return colorref; } #endif