rt-thread-official/components/rtgui/server/mouse.c

643 lines
17 KiB
C

/*
* File : mouse.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2009, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2009-10-16 Bernard first version
*/
#include "mouse.h"
#include <rtgui/region.h>
#include <rtgui/driver.h>
#include <rtgui/rtgui_system.h>
struct rtgui_cursor
{
/* screen byte per pixel */
rt_uint16_t bpp;
/* screen pitch */
rt_uint16_t screen_pitch;
/* current cursor x and y */
rt_uint16_t cx, cy;
#ifdef RTGUI_USING_MOUSE_CURSOR
/* cursor pitch */
rt_uint16_t cursor_pitch;
/* show cursor and show cursor count */
rt_bool_t show_cursor;
rt_base_t show_cursor_count;
/* cursor rect info */
rtgui_rect_t rect;
/* cursor image and saved cursor */
rtgui_image_t *cursor_image;
rt_uint8_t *cursor_saved;
#endif
#ifdef RTGUI_USING_WINMOVE
/* move window rect and border */
struct rtgui_topwin *topwin;
rtgui_rect_t win_rect;
rt_uint8_t *win_left, *win_right;
rt_uint8_t *win_top, *win_bottom;
rt_bool_t win_rect_show, win_rect_has_saved;
#endif
};
struct rtgui_cursor* _rtgui_cursor;
#ifdef RTGUI_USING_MOUSE_CURSOR
struct rt_mutex cursor_mutex;
static const rt_uint8_t * cursor_xpm[] = {
"16 16 35 1",
" c None",
". c #A0B8D0",
"+ c #F0F0F0",
"@ c #FFFFFF",
"# c #F0F8F0",
"$ c #A0B0D0",
"% c #90A8C0",
"& c #A0B0C0",
"* c #E0E8F0",
"= c #8090B0",
"- c #D0D8E0",
"; c #7080A0",
"> c #90A0B0",
", c #FFF8FF",
"' c #F0F8FF",
") c #607090",
"! c #8098B0",
"~ c #405060",
"{ c #405070",
"] c #506070",
"^ c #607080",
"/ c #708090",
"( c #7088A0",
"_ c #D0D0E0",
": c #607890",
"< c #C0D0E0",
"[ c #C0C8D0",
"} c #506880",
"| c #5F778F",
"1 c #D0D8F0",
"2 c #506080",
"3 c #C0C8E0",
"4 c #A0A8C0",
"5 c #405870",
"6 c #5F6F8F",
" . ",
" .. ",
" .+. ",
" .@#$ ",
" $@@+% ",
" &@@@*= ",
" %@@@@-; ",
" >@@,''-) ",
" !,''+)~{] ",
" ='-^*/ ",
" (_{:<[^ ",
" ;} |:12 ",
" / )345 ",
" 6}${ ",
" 5{ ",
" "};
static void rtgui_cursor_restore (void);
static void rtgui_cursor_save (void);
static void rtgui_cursor_show (void);
#endif
#ifdef RTGUI_USING_WINMOVE
static void rtgui_winrect_restore (void);
static void rtgui_winrect_save (void);
static void rtgui_winrect_show (void);
#endif
#define WIN_MOVE_BORDER 4
void rtgui_mouse_init()
{
const struct rtgui_graphic_driver* gd = rtgui_graphic_driver_get_default();
_rtgui_cursor = (struct rtgui_cursor*) rtgui_malloc(sizeof(struct rtgui_cursor));
rt_memset(_rtgui_cursor, 0, sizeof(struct rtgui_cursor));
#ifdef RTGUI_USING_MOUSE_CURSOR
rt_mutex_init(&cursor_mutex, "cursor", RT_IPC_FLAG_FIFO);
#endif
/* init cursor */
_rtgui_cursor->bpp = gd->bits_per_pixel/8;
_rtgui_cursor->screen_pitch = _rtgui_cursor->bpp * gd->width;
#ifdef RTGUI_USING_MOUSE_CURSOR
/* init cursor image */
_rtgui_cursor->cursor_image = rtgui_image_create_from_mem("xpm",
(rt_uint8_t*)cursor_xpm,
sizeof(cursor_xpm),
RT_TRUE);
if (_rtgui_cursor->cursor_image == RT_NULL)
{
rtgui_free(_rtgui_cursor);
_rtgui_cursor = RT_NULL;
return;
}
/* init rect */
_rtgui_cursor->rect.x1 = _rtgui_cursor->rect.y1 = 0;
_rtgui_cursor->rect.x2 = _rtgui_cursor->cursor_image->w;
_rtgui_cursor->rect.y2 = _rtgui_cursor->cursor_image->h;
_rtgui_cursor->cursor_pitch = _rtgui_cursor->cursor_image->w * _rtgui_cursor->bpp;
_rtgui_cursor->show_cursor = RT_TRUE;
_rtgui_cursor->show_cursor_count = 0;
_rtgui_cursor->cursor_saved = rtgui_malloc(_rtgui_cursor->cursor_image->w *
_rtgui_cursor->cursor_image->h * _rtgui_cursor->bpp);
#endif
#ifdef RTGUI_USING_WINMOVE
/* init window move save image */
_rtgui_cursor->win_rect_has_saved = RT_FALSE;
_rtgui_cursor->win_rect_show = RT_FALSE;
_rtgui_cursor->win_left = rtgui_malloc(_rtgui_cursor->bpp * gd->height * WIN_MOVE_BORDER);
_rtgui_cursor->win_right = rtgui_malloc(_rtgui_cursor->bpp * gd->height * WIN_MOVE_BORDER);
_rtgui_cursor->win_top = rtgui_malloc(_rtgui_cursor->bpp * gd->width * WIN_MOVE_BORDER);
_rtgui_cursor->win_bottom = rtgui_malloc(_rtgui_cursor->bpp * gd->width * WIN_MOVE_BORDER);
#endif
}
void rtgui_mouse_moveto(int x, int y)
{
#ifdef RTGUI_USING_MOUSE_CURSOR
rt_mutex_take(&cursor_mutex, RT_WAITING_FOREVER);
#endif
if (x != _rtgui_cursor->cx ||
y != _rtgui_cursor->cy)
{
#ifdef RTGUI_USING_WINMOVE
if (_rtgui_cursor->win_rect_show)
{
if (_rtgui_cursor->win_rect_has_saved == RT_TRUE)
{
rtgui_winrect_restore();
}
#ifdef RTGUI_USING_MOUSE_CURSOR
rtgui_mouse_hide_cursor();
#endif
/* move winrect */
rtgui_rect_moveto(&(_rtgui_cursor->win_rect), x - _rtgui_cursor->cx,
y - _rtgui_cursor->cy);
rtgui_winrect_save();
/* move current cursor */
_rtgui_cursor->cx = x;
_rtgui_cursor->cy = y;
#ifdef RTGUI_USING_MOUSE_CURSOR
/* show cursor */
rtgui_mouse_show_cursor();
#endif
/* show winrect */
rtgui_winrect_show();
}
else
#endif
{
#ifdef RTGUI_USING_MOUSE_CURSOR
rtgui_mouse_hide_cursor();
#endif
/* move current cursor */
_rtgui_cursor->cx = x;
_rtgui_cursor->cy = y;
#ifdef RTGUI_USING_MOUSE_CURSOR
/* show cursor */
rtgui_mouse_show_cursor();
#endif
}
}
#ifdef RTGUI_USING_MOUSE_CURSOR
rt_mutex_release(&cursor_mutex);
#endif
}
#ifdef RTGUI_USING_MOUSE_CURSOR
void rtgui_mouse_set_cursor_enable(rt_bool_t enable)
{
_rtgui_cursor->show_cursor = enable;
}
/* set current cursor image */
void rtgui_mouse_set_cursor(rtgui_image_t* cursor)
{
}
void rtgui_mouse_get_cursor_rect(rtgui_rect_t* rect)
{
if (rect != RT_NULL)
{
*rect = _rtgui_cursor->rect;
}
}
void rtgui_mouse_show_cursor()
{
if (_rtgui_cursor->show_cursor == RT_FALSE)
return;
_rtgui_cursor->show_cursor_count ++;
if (_rtgui_cursor->show_cursor_count == 1)
{
/* save show mouse area */
rtgui_cursor_save();
/* show mouse cursor */
rtgui_cursor_show();
}
}
void rtgui_mouse_hide_cursor()
{
if (_rtgui_cursor->show_cursor == RT_FALSE)
return;
if (_rtgui_cursor->show_cursor_count == 1)
{
/* display the cursor coverage area */
rtgui_cursor_restore();
}
_rtgui_cursor->show_cursor_count --;
}
rt_bool_t rtgui_mouse_is_intersect(rtgui_rect_t* r)
{
return rtgui_rect_is_intersect(&(_rtgui_cursor->rect), r) == RT_EOK? RT_TRUE : RT_FALSE;
}
/* display the saved cursor area to screen */
static void rtgui_cursor_restore()
{
rt_base_t idx, height, cursor_pitch;
rt_uint8_t *cursor_ptr, *fb_ptr;
fb_ptr = rtgui_graphic_driver_get_default_framebuffer() + _rtgui_cursor->cy * _rtgui_cursor->screen_pitch
+ _rtgui_cursor->cx * _rtgui_cursor->bpp;
cursor_ptr = _rtgui_cursor->cursor_saved;
height = (_rtgui_cursor->cy + _rtgui_cursor->cursor_image->h <
rtgui_graphic_driver_get_default()->height)? _rtgui_cursor->cursor_image->h :
rtgui_graphic_driver_get_default()->height - _rtgui_cursor->cy;
cursor_pitch = (_rtgui_cursor->cx + _rtgui_cursor->cursor_image->w <
rtgui_graphic_driver_get_default()->width)? _rtgui_cursor->cursor_pitch :
(rtgui_graphic_driver_get_default()->width - _rtgui_cursor->cx) * _rtgui_cursor->bpp;
for (idx = 0; idx < height; idx ++)
{
rt_memcpy(fb_ptr, cursor_ptr, cursor_pitch);
fb_ptr += _rtgui_cursor->screen_pitch;
cursor_ptr += _rtgui_cursor->cursor_pitch;
}
}
/* save the cursor coverage area from screen */
static void rtgui_cursor_save()
{
rt_base_t idx, height, cursor_pitch;
rt_uint8_t *cursor_ptr, *fb_ptr;
fb_ptr = _driver_get_default_framebuffer() + _rtgui_cursor->cy * _rtgui_cursor->screen_pitch +
_rtgui_cursor->cx * _rtgui_cursor->bpp;
cursor_ptr = _rtgui_cursor->cursor_saved;
height = (_rtgui_cursor->cy + _rtgui_cursor->cursor_image->h <
rtgui_graphic_driver_get_default()->height)? _rtgui_cursor->cursor_image->h :
rtgui_graphic_driver_get_default()->height - _rtgui_cursor->cy;
cursor_pitch = (_rtgui_cursor->cx + _rtgui_cursor->cursor_image->w <
rtgui_graphic_driver_get_default()->width)? _rtgui_cursor->cursor_pitch :
(rtgui_graphic_driver_get_default()->width - _rtgui_cursor->cx) * _rtgui_cursor->bpp;
for (idx = 0; idx < height; idx ++)
{
rt_memcpy(cursor_ptr, fb_ptr, cursor_pitch);
fb_ptr += _rtgui_cursor->screen_pitch;
cursor_ptr += _rtgui_cursor->cursor_pitch;
}
}
static void rtgui_cursor_show()
{
// FIXME: the prototype of set_pixel is using int so we have to use int
// as well. Might be uniformed with others in the future
int x, y;
rtgui_color_t* ptr;
rtgui_rect_t rect;
void (*set_pixel) (rtgui_color_t *c, int x, int y);
ptr = (rtgui_color_t*) _rtgui_cursor->cursor_image->data;
set_pixel = rtgui_graphic_driver_get_default()->ops->set_pixel;
rtgui_mouse_get_cursor_rect(&rect);
rtgui_rect_moveto(&rect, _rtgui_cursor->cx, _rtgui_cursor->cy);
/* draw each point */
for (y = rect.y1; y < rect.y2; y ++)
{
for (x = rect.x1; x < rect.x2; x++)
{
/* not alpha */
if ((*ptr >> 24) != 255)
{
set_pixel(ptr, x, y);
}
/* move to next color buffer */
ptr ++;
}
}
/* update rect */
rtgui_graphic_driver_screen_update(rtgui_graphic_driver_get_default(), &rect);
}
#endif
#ifdef RTGUI_USING_WINMOVE
void rtgui_winrect_set(struct rtgui_topwin* topwin)
{
/* set win rect show */
_rtgui_cursor->win_rect_show = RT_TRUE;
/* set win rect */
_rtgui_cursor->win_rect = topwin->title == RT_NULL? topwin->extent : RTGUI_WIDGET(topwin->title)->extent;
_rtgui_cursor->topwin = topwin;
}
rt_bool_t rtgui_winrect_moved_done(rtgui_rect_t* winrect, struct rtgui_topwin** topwin)
{
rt_bool_t moved = RT_FALSE;
/* no win rect */
if (winrect == RT_NULL) return RT_FALSE;
/* restore winrect */
if (_rtgui_cursor->win_rect_has_saved)
{
rtgui_winrect_restore();
moved = RT_TRUE;
}
/* clear win rect show */
_rtgui_cursor->win_rect_show = RT_FALSE;
_rtgui_cursor->win_rect_has_saved = RT_FALSE;
/* return win rect */
*winrect = _rtgui_cursor->win_rect;
*topwin = _rtgui_cursor->topwin;
return moved;
}
rt_bool_t rtgui_winrect_is_moved()
{
return _rtgui_cursor->win_rect_show;
}
/* show winrect */
static void rtgui_winrect_show()
{
rt_uint16_t x, y;
rtgui_color_t c;
rtgui_rect_t screen_rect, win_rect, win_rect_inner;
void (*set_pixel) (rtgui_color_t *c, int x, int y);
c = black;
set_pixel = rtgui_graphic_driver_get_default()->ops->set_pixel;
win_rect = _rtgui_cursor->win_rect;
win_rect_inner = win_rect;
rtgui_rect_inflate(&win_rect_inner, -WIN_MOVE_BORDER);
rtgui_graphic_driver_get_rect(rtgui_graphic_driver_get_default(),
&screen_rect);
rtgui_rect_intersect(&screen_rect, &win_rect);
rtgui_rect_intersect(&screen_rect, &win_rect_inner);
/* draw left */
for (y = win_rect.y1; y < win_rect.y2; y ++)
{
for (x = win_rect.x1; x < win_rect_inner.x1; x++)
if ((x + y) & 0x01) set_pixel(&c, x, y);
}
/* draw right */
for (y = win_rect.y1; y < win_rect.y2; y ++)
{
for (x = win_rect_inner.x2; x < win_rect.x2; x++)
if ((x + y) & 0x01) set_pixel(&c, x, y);
}
/* draw top border */
for (y = win_rect.y1; y < win_rect_inner.y1; y ++)
{
for (x = win_rect_inner.x1; x < win_rect_inner.x2; x++)
if ((x + y) & 0x01) set_pixel(&c, x, y);
}
/* draw bottom border */
for (y = win_rect_inner.y2; y < win_rect.y2; y ++)
{
for (x = win_rect_inner.x1; x < win_rect_inner.x2; x++)
if ((x + y) & 0x01) set_pixel(&c, x, y);
}
/* update rect */
rtgui_graphic_driver_screen_update(rtgui_graphic_driver_get_default(), &win_rect);
}
#define display_direct_memcpy(src, dest, src_pitch, dest_pitch, height, len) \
for (idx = 0; idx < height; idx ++) \
{ \
rt_memcpy(dest, src, len); \
src += src_pitch; \
dest += dest_pitch; \
}
static void rtgui_winrect_restore()
{
rt_uint8_t *winrect_ptr, *fb_ptr, *driver_fb;
int winrect_pitch, idx;
rtgui_rect_t screen_rect, win_rect;
driver_fb = rtgui_graphic_driver_get_default_framebuffer();
win_rect = _rtgui_cursor->win_rect;
rtgui_graphic_driver_get_rect(rtgui_graphic_driver_get_default(),
&screen_rect);
rtgui_rect_intersect(&screen_rect, &win_rect);
/* restore winrect left */
fb_ptr = driver_fb + win_rect.y1 * _rtgui_cursor->screen_pitch +
win_rect.x1 * _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_left;
winrect_pitch = WIN_MOVE_BORDER * _rtgui_cursor->bpp;
display_direct_memcpy(winrect_ptr, fb_ptr, winrect_pitch, _rtgui_cursor->screen_pitch,
(win_rect.y2 - win_rect.y1), winrect_pitch);
/* restore winrect right */
fb_ptr = driver_fb + win_rect.y1 * _rtgui_cursor->screen_pitch +
(win_rect.x2 - WIN_MOVE_BORDER) * _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_right;
winrect_pitch = WIN_MOVE_BORDER * _rtgui_cursor->bpp;
display_direct_memcpy(winrect_ptr, fb_ptr, winrect_pitch, _rtgui_cursor->screen_pitch,
(win_rect.y2 - win_rect.y1), winrect_pitch);
/* restore winrect top */
fb_ptr = driver_fb + win_rect.y1 * _rtgui_cursor->screen_pitch +
(win_rect.x1 + WIN_MOVE_BORDER)* _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_top;
winrect_pitch = (win_rect.x2 - win_rect.x1 - 2 * WIN_MOVE_BORDER) * _rtgui_cursor->bpp;
display_direct_memcpy(winrect_ptr, fb_ptr, winrect_pitch, _rtgui_cursor->screen_pitch,
WIN_MOVE_BORDER, winrect_pitch);
/* restore winrect bottom */
fb_ptr = driver_fb + (win_rect.y2 - WIN_MOVE_BORDER) * _rtgui_cursor->screen_pitch +
(win_rect.x1 + WIN_MOVE_BORDER) * _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_bottom;
display_direct_memcpy(winrect_ptr, fb_ptr, winrect_pitch, _rtgui_cursor->screen_pitch,
WIN_MOVE_BORDER, winrect_pitch);
}
static void rtgui_winrect_save()
{
rt_uint8_t *winrect_ptr, *fb_ptr, *driver_fb;
int winrect_pitch, idx;
rtgui_rect_t screen_rect, win_rect;
driver_fb = rtgui_graphic_driver_get_default_framebuffer();
win_rect = _rtgui_cursor->win_rect;
rtgui_graphic_driver_get_rect(rtgui_graphic_driver_get_default(),
&screen_rect);
rtgui_rect_intersect(&screen_rect, &win_rect);
/* set winrect has saved */
_rtgui_cursor->win_rect_has_saved = RT_TRUE;
/* save winrect left */
fb_ptr = driver_fb + win_rect.y1 * _rtgui_cursor->screen_pitch +
win_rect.x1 * _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_left;
winrect_pitch = WIN_MOVE_BORDER * _rtgui_cursor->bpp;
display_direct_memcpy(fb_ptr, winrect_ptr, _rtgui_cursor->screen_pitch, winrect_pitch,
(win_rect.y2 - win_rect.y1), winrect_pitch);
/* save winrect right */
fb_ptr = driver_fb + win_rect.y1 * _rtgui_cursor->screen_pitch +
(win_rect.x2 - WIN_MOVE_BORDER) * _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_right;
winrect_pitch = WIN_MOVE_BORDER * _rtgui_cursor->bpp;
display_direct_memcpy(fb_ptr, winrect_ptr, _rtgui_cursor->screen_pitch, winrect_pitch,
(win_rect.y2 - win_rect.y1), winrect_pitch);
/* save winrect top */
fb_ptr = driver_fb + win_rect.y1 * _rtgui_cursor->screen_pitch +
(win_rect.x1 + WIN_MOVE_BORDER)* _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_top;
winrect_pitch = (win_rect.x2 - win_rect.x1 - 2 * WIN_MOVE_BORDER) * _rtgui_cursor->bpp;
display_direct_memcpy(fb_ptr, winrect_ptr, _rtgui_cursor->screen_pitch, winrect_pitch,
WIN_MOVE_BORDER, winrect_pitch);
/* save winrect bottom */
fb_ptr = driver_fb + (win_rect.y2 - WIN_MOVE_BORDER) * _rtgui_cursor->screen_pitch +
(win_rect.x1 + WIN_MOVE_BORDER) * _rtgui_cursor->bpp;
winrect_ptr = _rtgui_cursor->win_bottom;
display_direct_memcpy(fb_ptr, winrect_ptr, _rtgui_cursor->screen_pitch, winrect_pitch,
WIN_MOVE_BORDER, winrect_pitch);
}
#endif
void rtgui_mouse_monitor_append(rtgui_list_t* head, rtgui_rect_t* rect)
{
struct rtgui_mouse_monitor* mmonitor;
/* check parameters */
if (head == RT_NULL || rect == RT_NULL) return;
/* create a mouse monitor node */
mmonitor = (struct rtgui_mouse_monitor*) rtgui_malloc (sizeof(struct rtgui_mouse_monitor));
if (mmonitor == RT_NULL) return; /* no memory */
/* set mouse monitor node */
mmonitor->rect = *rect;
rtgui_list_init(&(mmonitor->list));
/* append to list */
rtgui_list_append(head, &(mmonitor->list));
}
void rtgui_mouse_monitor_remove(rtgui_list_t* head, rtgui_rect_t* rect)
{
struct rtgui_list_node* node;
struct rtgui_mouse_monitor* mmonitor;
/* check parameters */
if (head == RT_NULL || rect == RT_NULL) return;
for (node = head->next; node != RT_NULL; node = node->next)
{
mmonitor = rtgui_list_entry(node, struct rtgui_mouse_monitor, list);
if (mmonitor->rect.x1 == rect->x1 &&
mmonitor->rect.x2 == rect->x2 &&
mmonitor->rect.y1 == rect->y1 &&
mmonitor->rect.y2 == rect->y2)
{
/* found node */
rtgui_list_remove(head, node);
rtgui_free(mmonitor);
return ;
}
}
}
rt_bool_t rtgui_mouse_monitor_contains_point(rtgui_list_t* head, int x, int y)
{
struct rtgui_list_node* node;
/* check parameter */
if (head == RT_NULL) return RT_FALSE;
rtgui_list_foreach(node, head)
{
struct rtgui_mouse_monitor* monitor = rtgui_list_entry(node,
struct rtgui_mouse_monitor, list);
if (rtgui_rect_contains_point(&(monitor->rect), x, y) == RT_EOK)
{
return RT_TRUE;
}
}
return RT_FALSE;
}