/* Jinete - a GUI library * Copyright (c) 2003, 2004, 2005, 2007, David A. Capello * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of the Jinete nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "jinete/intern.h" #include "jinete/manager.h" #include "jinete/rect.h" #include "jinete/system.h" #include "jinete/theme.h" #include "jinete/widget.h" /* Global output bitmap. */ BITMAP *ji_screen = NULL; /* Global timer. */ volatile int ji_clock = 0; /* Hook to translate strings. */ static const char *(*strings_hook)(const char *msgid) = NULL; /* Current mouse cursor type. */ static int m_cursor; static BITMAP *sprite_cursor = NULL; static int focus_x; static int focus_y; /* Mouse information (button and position). */ static volatile int m_b[2]; static int m_x[2]; static int m_y[2]; static int m_z[2]; static bool moved; /* For double click management. */ static volatile int click_clock = 0; static volatile int click_level = JI_CLICK_NOT; static volatile int click_mouse_b = 0; /* Local routines. */ static void set_cursor(BITMAP *bmp, int x, int y); static void clock_inc(void); static void check_click(void); static void clock_inc(void) { ji_clock++; } END_OF_STATIC_FUNCTION(clock_inc); /* Based on "dclick_check" from allegro/src/gui.c. */ static void check_click(void) { /* Waiting mouse released... */ if (click_level == JI_CLICK_START) { /* The button was released. */ if (!m_b[0]) { click_clock = 0; click_level = JI_CLICK_RELEASE; } /* The button continue pressed. */ else { /* Does mouse button change? */ if (click_mouse_b != m_b[0]) { /* Start again with this new button. */ click_clock = 0; click_level = JI_CLICK_START; click_mouse_b = m_b[0]; } else click_clock++; } } /* Waiting second mouse click... */ else if (click_level == JI_CLICK_RELEASE) { /* The button is pressed again. */ if (m_b[0]) { /* Is the same button? */ if (m_b[0] == click_mouse_b) { click_level = JI_CLICK_AGAIN; } /* If it's other button, start again with this one. */ else { click_clock = 0; click_level = JI_CLICK_START; click_mouse_b = m_b[0]; } } else click_clock++; } if (click_clock > 10) click_level = JI_CLICK_NOT; } END_OF_STATIC_FUNCTION(check_click); static void set_cursor(BITMAP *bmp, int x, int y) { sprite_cursor = bmp; focus_x = x; focus_y = y; set_mouse_sprite(bmp); set_mouse_sprite_focus(x, y); } int _ji_system_init(void) { /* Update screen pointer. */ ji_set_screen(screen); /* Install timer related stuff. */ LOCK_VARIABLE(ji_clock); LOCK_VARIABLE(m_b); LOCK_VARIABLE(click_clock); LOCK_VARIABLE(click_level); LOCK_VARIABLE(click_mouse_b); LOCK_FUNCTION(clock_inc); LOCK_FUNCTION(check_click); if ((install_int_ex(clock_inc, BPS_TO_TIMER(JI_TICKS_PER_SEC)) < 0) || (install_int(check_click, 20) < 0)) return -1; ji_mouse_poll(); moved = TRUE; m_cursor = JI_CURSOR_NULL; return 0; } void _ji_system_exit(void) { ji_set_screen(NULL); remove_int(check_click); remove_int(clock_inc); } void ji_set_screen(BITMAP *bmp) { int cursor = ji_mouse_get_cursor(); /* get mouse cursor */ ji_mouse_set_cursor(JI_CURSOR_NULL); ji_screen = bmp; if (ji_screen) { JWidget manager = ji_get_default_manager(); /* update default-manager size */ if (manager && (jrect_w(manager->rc) != JI_SCREEN_W || jrect_h(manager->rc) != JI_SCREEN_H)) { JRect rect = jrect_new(0, 0, JI_SCREEN_W, JI_SCREEN_H); jwidget_set_rect(manager, rect); jrect_free(rect); } ji_mouse_set_cursor(cursor); /* restore mouse cursor */ } } void ji_set_translation_hook(const char *(*gettext) (const char *msgid)) { strings_hook = gettext; } const char *ji_translate_string(const char *msgid) { if (strings_hook) return (*strings_hook) (msgid); else return msgid; } int ji_mouse_get_cursor(void) { return m_cursor; } int ji_mouse_set_cursor(int type) { JTheme theme = ji_get_theme(); int old = m_cursor; m_cursor = type; if (m_cursor == JI_CURSOR_NULL) { show_mouse(NULL); set_cursor(NULL, 0, 0); } else { show_mouse(NULL); if (theme->set_cursor) { BITMAP *sprite; int x = 0; int y = 0; sprite = (*theme->set_cursor)(m_cursor, &x, &y); set_cursor(sprite, x, y); } if (ji_screen == screen) show_mouse(ji_screen); } return old; } /** * Use this routine if your "ji_screen" isn't Allegro's "screen" so * you must to draw the cursor by your self using this routine. */ void ji_mouse_draw_cursor() { if (sprite_cursor != NULL) { int x = m_x[0]-focus_x; int y = m_y[0]-focus_y; JRect rect = jrect_new(x, y, x+sprite_cursor->w, y+sprite_cursor->h); jwidget_invalidate_rect(ji_get_default_manager(), rect); draw_sprite(ji_screen, sprite_cursor, x, y); jrect_free(rect); } } /* Returns TRUE if the mouse moved. */ bool ji_mouse_poll(void) { m_b[1] = m_b[0]; m_x[1] = m_x[0]; m_y[1] = m_y[0]; m_z[1] = m_z[0]; poll_mouse(); m_b[0] = mouse_b; m_z[0] = mouse_z; if (ji_screen == screen) { m_x[0] = mouse_x; m_y[0] = mouse_y; } else { m_x[0] = JI_SCREEN_W * mouse_x / SCREEN_W; m_y[0] = JI_SCREEN_H * mouse_y / SCREEN_H; } if ((m_x[0] != m_x[1]) || (m_y[0] != m_y[1])) { poll_mouse(); if (ji_screen == screen) { m_x[0] = mouse_x; m_y[0] = mouse_y; } else { m_x[0] = JI_SCREEN_W * mouse_x / SCREEN_W; m_y[0] = JI_SCREEN_H * mouse_y / SCREEN_H; } moved = TRUE; } if (moved) { moved = FALSE; return TRUE; } else return FALSE; } void ji_mouse_set_position(int x, int y) { moved = TRUE; m_x[0] = m_x[1] = x; m_y[0] = m_y[1] = y; if (ji_screen == screen) { position_mouse(x, y); } else { position_mouse(SCREEN_W * x / JI_SCREEN_W, SCREEN_H * y / JI_SCREEN_H); } } int ji_mouse_x(int antique) { return m_x[antique & 1]; } int ji_mouse_y(int antique) { return m_y[antique & 1]; } int ji_mouse_z(int antique) { return m_z[antique & 1]; } int ji_mouse_b(int antique) { return m_b[antique & 1]; } bool ji_mouse_control_infinite_scroll(JRect rect) { int x, y, u, v; u = ji_mouse_x(0); v = ji_mouse_y(0); if (u <= rect->x1) x = rect->x2-2; else if (u >= rect->x2-1) x = rect->x1+1; else x = u; if (v <= rect->y1) y = rect->y2-2; else if (v >= rect->y2-1) y = rect->y1+1; else y = v; if ((x != u) || (y != v)) { ji_mouse_set_position(x, y); return TRUE; } else return FALSE; } int ji_mouse_get_click_button(void) { return click_mouse_b; } int ji_mouse_get_click_level(void) { return click_level; } void ji_mouse_set_click_level(int level) { click_level = level; if (level == JI_CLICK_START) { click_clock = 0; click_mouse_b = m_b[0]; } }