netsurf/atari/gemtk/guiwin.c

616 lines
17 KiB
C

//#include "global.h"
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <cflib.h>
#include <mt_gem.h>
#include "gemtk.h"
//#define DEBUG_PRINT(x) printf x
#define DEBUG_PRINT(x)
struct gui_window_s {
short handle;
guiwin_event_handler_f handler_func;
uint32_t flags;
uint32_t state;
OBJECT * toolbar;
short toolbar_idx;
struct guiwin_scroll_info_s scroll_info;
void *user_data;
struct gui_window_s *next, *prev;
};
static GUIWIN * winlist;
static VdiHdl v_vdi_h = -1;
static short work_out[57];
static void move_rect(GRECT *rect, int dx, int dy)
{
INT16 xy[ 8];
long dum = 0L;
GRECT g;
while( !wind_update(BEG_UPDATE));
graf_mouse(M_OFF, 0L);
/* get intersection with screen area */
wind_get_grect(0, WF_CURRXYWH, &g);
rc_intersect(&g, rect);
xy[0] = rect->g_x;
xy[1] = rect->g_y;
xy[2] = xy[0] + rect->g_w-1;
xy[3] = xy[1] + rect->g_h-1;
xy[4] = xy[0] + dx;
xy[5] = xy[1] + dy;
xy[6] = xy[2] + dx;
xy[7] = xy[3] + dy;
vro_cpyfm(v_vdi_h, S_ONLY, xy, (MFDB *)&dum, (MFDB *)&dum);
graf_mouse(M_ON, 0L);
wind_update(END_UPDATE);
}
static short preproc_wm(GUIWIN * gw, EVMULT_OUT *ev_out, short msg[8])
{
GRECT g, g_ro, tb_area, tb_area_ro;
short retval = 1;
int val = 1;
struct guiwin_scroll_info_s *slid;
switch(msg[0]) {
case WM_ARROWED:
if((gw->flags & GW_FLAG_CUSTOM_SCROLLING) == 0) {
slid = guiwin_get_scroll_info(gw);
guiwin_get_grect(gw, GUIWIN_AREA_CONTENT, &g);
g_ro = g;
switch(msg[4]) {
case WA_UPPAGE:
val = g.g_h/slid->y_unit_px;
slid->y_pos = MAX(0, slid->y_pos-val);
guiwin_update_slider(gw, GUIWIN_VSLIDER);
guiwin_send_redraw(gw, &g_ro);
break;
case WA_UPLINE:
slid->y_pos = MAX(0, slid->y_pos-1);
guiwin_update_slider(gw, GUIWIN_VSLIDER);
if(!guiwin_has_intersection(gw, NULL)){
// blit screen area:
g.g_h -= slid->y_unit_px;
move_rect(&g, 0, +slid->y_unit_px);
g.g_y = g_ro.g_y;
g.g_h = slid->y_unit_px;
// redraw new content:
guiwin_send_redraw(gw, &g);
} else {
// let the draw implementation handle intersections:
guiwin_send_redraw(gw, &g_ro);
}
break;
case WA_DNPAGE:
val = g.g_h/slid->y_unit_px;
slid->y_pos = MIN(slid->y_pos_max, slid->y_pos+val);
guiwin_update_slider(gw, GUIWIN_VSLIDER);
guiwin_send_redraw(gw, &g_ro);
break;
case WA_DNLINE:
slid->y_pos = MIN(slid->y_pos_max, slid->y_pos+1);
guiwin_update_slider(gw, GUIWIN_VSLIDER);
if(!guiwin_has_intersection(gw, NULL)){
// blit screen area:
g.g_y += slid->y_unit_px;
g.g_h -= slid->y_unit_px;
move_rect(&g, 0, -slid->y_unit_px);
g.g_y = g_ro.g_y + g_ro.g_h - slid->y_unit_px;
g.g_h = slid->y_unit_px;
// redraw new content:
guiwin_send_redraw(gw, &g);
} else {
// let the draw implementation handle intersections:
guiwin_send_redraw(gw, &g_ro);
}
break;
case WA_LFPAGE:
val = g.g_w/slid->x_unit_px;
slid->x_pos = MAX(0, slid->x_pos-val);
guiwin_update_slider(gw, GUIWIN_HSLIDER);
guiwin_send_redraw(gw, &g_ro);
break;
case WA_LFLINE:
slid->x_pos = MAX(0, slid->x_pos-1);
guiwin_update_slider(gw, GUIWIN_HSLIDER);
if(!guiwin_has_intersection(gw, NULL)){
// blit screen area:
g.g_x -= slid->x_unit_px;
move_rect(&g, 0, +slid->x_unit_px);
// redraw new content:
g.g_x = g_ro.g_x;
g.g_w = slid->x_unit_px;
guiwin_send_redraw(gw, &g);
} else {
// let the draw implementation handle intersections:
guiwin_send_redraw(gw, &g_ro);
}
// partial redraw
break;
case WA_RTPAGE:
val = g.g_w/slid->x_unit_px;
slid->x_pos = MIN(slid->x_pos_max, slid->x_pos+val);
guiwin_update_slider(gw, GUIWIN_HSLIDER);
guiwin_send_redraw(gw, &g_ro);
break;
case WA_RTLINE:
slid->x_pos = MIN(slid->x_pos_max, slid->x_pos+1);
guiwin_update_slider(gw, GUIWIN_HSLIDER);
if(!guiwin_has_intersection(gw, NULL)){
// blit remaining area:
g.g_x += slid->x_unit_px;
g.g_w -= slid->y_unit_px;
move_rect(&g, 0, -slid->x_unit_px);
// redraw new content:
g.g_x = g_ro.g_x + g_ro.g_w - slid->x_unit_px;
g.g_h = slid->x_unit_px;
guiwin_send_redraw(gw, &g);
} else {
// let the draw implementation handle intersections:
guiwin_send_redraw(gw, &g_ro);
}
break;
default:
break;
}
}
break;
case WM_TOPPED:
wind_set(gw->handle, WF_TOP, 1, 0, 0, 0);
break;
case WM_MOVED:
wind_get_grect(gw->handle, WF_CURRXYWH, &g);
wind_set(gw->handle, WF_CURRXYWH, msg[4], msg[5], g.g_w, g.g_h);
break;
case WM_SIZED:
case WM_REPOSED:
wind_get_grect(gw->handle, WF_CURRXYWH, &g);
wind_set(gw->handle, WF_CURRXYWH, g.g_x, g.g_y, msg[6], msg[7]);
if((gw->flags & GW_FLAG_CUSTOM_SCROLLING) == 0) {
if(guiwin_update_slider(gw, GUIWIN_VH_SLIDER)){
guiwin_send_redraw(gw, NULL);
}
}
break;
case WM_FULLED:
wind_get_grect(gw->handle, WF_FULLXYWH, &g);
wind_set_grect(gw->handle, WF_CURRXYWH, &g);
if((gw->flags & GW_FLAG_CUSTOM_SCROLLING) == 0) {
if(guiwin_update_slider(gw, GUIWIN_VH_SLIDER)){
guiwin_send_redraw(gw, NULL);
}
}
break;
case WM_ICONIFY:
wind_set(gw->handle, WF_ICONIFY, msg[4], msg[5], msg[6], msg[7]);
gw->state |= GW_STATUS_ICONIFIED;
break;
case WM_UNICONIFY:
wind_set(gw->handle, WF_UNICONIFY, msg[4], msg[5], msg[6], msg[7]);
gw->state &= ~(GW_STATUS_ICONIFIED);
break;
case WM_SHADED:
gw->state |= GW_STATUS_SHADED;
break;
case WM_UNSHADED:
gw->state &= ~(GW_STATUS_SHADED);
break;
case WM_REDRAW:
if ((gw->flags & GW_FLAG_CUSTOM_TOOLBAR) == 0) {
guiwin_get_grect(gw, GUIWIN_AREA_TOOLBAR, &tb_area_ro);
tb_area = tb_area_ro;
if(rc_intersect((GRECT*)&msg[4], &tb_area)) {
gw->toolbar[gw->toolbar_idx].ob_x = tb_area_ro.g_x;
gw->toolbar[gw->toolbar_idx].ob_width = tb_area_ro.g_w;
gw->toolbar[gw->toolbar_idx].ob_y = tb_area_ro.g_y;
gw->toolbar[gw->toolbar_idx].ob_height = tb_area_ro.g_h;
wind_get_grect(gw->handle, WF_FIRSTXYWH, &g);
while (g.g_h > 0 || g.g_w > 0) {
if(rc_intersect(&tb_area_ro, &g)) {
objc_draw(gw->toolbar, gw->toolbar_idx, 8, g.g_x, g.g_y,
g.g_w, g.g_h);
}
wind_get_grect(gw->handle, WF_NEXTXYWH, &g);
}
}
}
break;
default:
retval = 0;
break;
}
return(retval);
}
short guiwin_dispatch_event(EVMULT_IN *ev_in, EVMULT_OUT *ev_out, short msg[8])
{
GUIWIN *dest;
short retval = 0;
if( (ev_out->emo_events & MU_MESAG) != 0 ) {
DEBUG_PRINT(("guiwin_handle_event_multi_fast: %d\n", msg[0]));
switch (msg[0]) {
case WM_REDRAW:
case WM_CLOSED:
case WM_TOPPED:
case WM_ARROWED:
case WM_HSLID:
case WM_VSLID:
case WM_FULLED:
case WM_SIZED:
case WM_REPOSED:
case WM_MOVED:
case WM_NEWTOP:
case WM_UNTOPPED:
case WM_ONTOP:
case WM_BOTTOM:
case WM_ICONIFY:
case WM_UNICONIFY:
case WM_ALLICONIFY:
case WM_TOOLBAR:
case AP_DRAGDROP:
case AP_TERM:
case AP_TFAIL:
dest = guiwin_find(msg[3]);
if (dest) {
DEBUG_PRINT(("Found WM_ dest: %p (%d), flags: %d, cb: %p\n", dest, dest->handle, dest->flags, dest->handler_func));
if (dest->flags&GW_FLAG_PREPROC_WM) {
retval = preproc_wm(dest, ev_out, msg);
if(((retval == 0)||(dest->flags&GW_FLAG_RECV_PREPROC_WM))) {
retval = dest->handler_func(dest, ev_out, msg);
}
} else {
if (dest->handler_func) {
retval = dest->handler_func(dest, ev_out, msg);
}
}
}
break;
}
} else {
short info[4];
wind_get( 0, WF_TOP, &info[0], &info[1], &info[2], &info[3]);
if(info[0] != 0 && info[1] == gl_apid) {
dest = guiwin_find(info[0]);
if(dest == NULL || dest->handler_func == NULL)
return(0);
if( (ev_out->emo_events & MU_BUTTON) != 0) {
DEBUG_PRINT(("Found MU_BUTTON dest: %p (%d), flags: %d, cb: %p\n", dest, dest->handle, dest->flags, dest->handler_func));
// toolbar handling:
if((dest->flags & GW_FLAG_CUSTOM_TOOLBAR) == 0 &&
dest->toolbar != NULL) {
GRECT tb_area;
guiwin_get_grect(dest, GUIWIN_AREA_TOOLBAR, &tb_area);
if (POINT_WITHIN(ev_out->emo_mouse.p_x,
ev_out->emo_mouse.p_y, tb_area)) {
// send WM_TOOLBAR message
dest->toolbar[dest->toolbar_idx].ob_x = tb_area.g_x;
dest->toolbar[dest->toolbar_idx].ob_y = tb_area.g_y;
short obj_idx = objc_find(dest->toolbar,
dest->toolbar_idx, 8,
ev_out->emo_mouse.p_x,
ev_out->emo_mouse.p_y);
short msg_out[8] = {WM_TOOLBAR, gl_apid, 0, dest->handle,
obj_idx, ev_out->emo_mclicks, ev_out->emo_kmeta, 0
};
short oldevents = ev_out->emo_events;
ev_out->emo_events = MU_MESAG;
dest->handler_func(dest, ev_out, msg_out);
ev_out->emo_events = oldevents;
retval = 1;
} else {
dest->handler_func(dest, ev_out, msg);
}
}
} else if(ev_out->emo_events & MU_KEYBD) {
dest->handler_func(dest, ev_out, msg);
}
}
}
return(retval);
}
short guiwin_init(void)
{
if(v_vdi_h == -1) {
short dummy;
static short work_in[12] = {1,1,1,1,1,1,1,1,1,1,2,1};
v_vdi_h=graf_handle(&dummy, &dummy, &dummy, &dummy);
v_opnvwk(work_in, &v_vdi_h, work_out);
}
return(0);
}
void guiwin_exit(void)
{
v_clsvwk(v_vdi_h);
}
GUIWIN * guiwin_add(short handle, uint32_t flags, guiwin_event_handler_f cb)
{
GUIWIN *win = calloc(sizeof(GUIWIN),1);
assert(win!=NULL);
DEBUG_PRINT(("guiwin_add: %d, %p, cb: %p\n", handle, win, cb));
win->handle = handle;
win->handler_func = cb;
win->flags = flags;
if (winlist == NULL) {
winlist = win;
win->next = NULL;
win->prev = NULL;
} else {
GUIWIN *tmp = winlist;
while( tmp->next != NULL ) {
tmp = tmp->next;
}
tmp->next = win;
win->prev = tmp;
win->next = NULL;
}
return(win);
}
GUIWIN *guiwin_find(short handle)
{
GUIWIN *g;
DEBUG_PRINT(("guiwin_find: handle: %d\n", handle));
for( g = winlist; g != NULL; g=g->next ) {
DEBUG_PRINT(("guiwin search: %d\n", g->handle));
if(g->handle == handle) {
DEBUG_PRINT(("guiwin_find: %p\n", g));
return(g);
}
}
return(NULL);
}
GUIWIN *guiwin_validate_ptr(GUIWIN *win)
{
GUIWIN *g;
for( g = winlist; g != NULL; g=g->next ) {
DEBUG_PRINT(("guiwin guiwin_validate_ptr check: %p\n", g));
if(g == win) {
DEBUG_PRINT(("guiwin_validate_ptr valid: %p\n", g));
return(g);
}
}
return(NULL);
}
short guiwin_remove(GUIWIN *win)
{
win = guiwin_validate_ptr(win);
if (win == NULL)
return(-1);
/* unlink the window: */
if(win->prev != NULL ) {
win->prev->next = win->next;
} else {
winlist = win->next;
}
if (win->next != NULL) {
win->next->prev = win->prev;
}
free(win);
return(0);
}
void guiwin_get_grect(GUIWIN *win, enum guwin_area_e mode, GRECT *dest)
{
wind_get_grect(win->handle, WF_WORKXYWH, dest);
if (mode == GUIWIN_AREA_CONTENT) {
GRECT tb_area;
guiwin_get_grect(win, GUIWIN_AREA_TOOLBAR, &tb_area);
if (win->flags & GW_FLAG_HAS_VTOOLBAR) {
dest->g_x += tb_area.g_w;
dest->g_w -= tb_area.g_w;
} else {
dest->g_y += tb_area.g_h;
dest->g_h -= tb_area.g_h;
}
} else if (mode == GUIWIN_AREA_TOOLBAR) {
if (win->toolbar != NULL) {
if (win->flags & GW_FLAG_HAS_VTOOLBAR) {
dest->g_w = win->toolbar[win->toolbar_idx].ob_width;
} else {
dest->g_h = win->toolbar[win->toolbar_idx].ob_height;
}
} else {
dest->g_h = 0;
dest->g_w = 0;
}
}
}
bool guiwin_update_slider(GUIWIN *win, short mode)
{
GRECT viewport;
struct guiwin_scroll_info_s * slid;
unsigned long size, pos;
int old_x, old_y;
short handle = guiwin_get_handle(win);
guiwin_get_grect(win, GUIWIN_AREA_CONTENT, &viewport);
slid = guiwin_get_scroll_info(win);
old_x = slid->x_pos;
old_y = slid->y_pos;
if((mode & GUIWIN_VSLIDER) && (slid->y_unit_px > 0)) {
if ( slid->y_pos_max < (long)viewport.g_h/slid->y_unit_px)
size = 1000L;
else
size = MAX( 50L, (unsigned long)viewport.g_h*1000L/
(unsigned long)(slid->y_unit_px*slid->y_pos_max));
wind_set(handle, WF_VSLSIZE, (int)size, 0, 0, 0);
if (slid->y_pos_max > (long)viewport.g_h/slid->y_unit_px) {
pos = (unsigned long)slid->y_pos *1000L/
(unsigned long)(slid->y_pos_max-viewport.g_h/slid->y_unit_px);
wind_set(handle, WF_VSLIDE, (int)pos, 0, 0, 0);
} else if (slid->y_pos) {
slid->y_pos = 0;
wind_set(handle, WF_VSLIDE, 0, 0, 0, 0);
}
}
if((mode & GUIWIN_HSLIDER) && (slid->x_unit_px > 0)) {
if ( slid->x_pos_max < (long)viewport.g_w/slid->x_unit_px)
size = 1000L;
else
size = MAX( 50L, (unsigned long)viewport.g_w*1000L/
(unsigned long)(slid->x_unit_px*slid->x_pos_max));
wind_set(handle, WF_HSLSIZE, (int)size, 0, 0, 0);
if( slid->x_pos_max > (long)viewport.g_w/slid->x_unit_px) {
pos = (unsigned long)slid->x_pos*1000L/
(unsigned long)(slid->x_pos_max-viewport.g_w/slid->x_unit_px);
wind_set(handle, WF_HSLIDE, (int)pos, 0, 0, 0);
} else if (slid->x_pos) {
slid->x_pos = 0;
wind_set(handle, WF_HSLIDE, 0, 0, 0, 0);
}
}
if(old_x != slid->x_pos || old_y != slid->y_pos){
return(true);
}
return(false);
}
short guiwin_get_handle(GUIWIN *win)
{
return(win->handle);
}
uint32_t guiwin_get_state(GUIWIN *win)
{
return(win->state);
}
void guiwin_set_event_handler(GUIWIN *win,guiwin_event_handler_f cb)
{
win->handler_func = cb;
}
void guiwin_set_toolbar(GUIWIN *win, OBJECT *toolbar, short idx, uint32_t flags)
{
win->toolbar = toolbar;
win->toolbar_idx = idx;
if(flags & GW_FLAG_HAS_VTOOLBAR) {
win->flags |= GW_FLAG_HAS_VTOOLBAR;
}
}
void guiwin_set_user_data(GUIWIN *win, void *data)
{
win->user_data = data;
}
void *guiwin_get_user_data(GUIWIN *win)
{
return(win->user_data);
}
struct guiwin_scroll_info_s *guiwin_get_scroll_info(GUIWIN *win) {
return(&win->scroll_info);
}
void guiwin_send_redraw(GUIWIN *win, GRECT *area)
{
short msg[8];
GRECT work;
if(area == NULL) {
guiwin_get_grect(win, GUIWIN_AREA_WORK, &work);
area = &work;
}
msg[0] = WM_REDRAW;
msg[1] = gl_apid;
msg[2] = 0;
msg[3] = win->handle;
msg[4] = area->g_x;
msg[5] = area->g_y;
msg[6] = area->g_w;
msg[7] = area->g_h;
appl_write(gl_apid, 16, &msg);
}
bool guiwin_has_intersection(GUIWIN *win, GRECT *work)
{
GRECT area, mywork;
bool retval = false;
if (work == NULL) {
guiwin_get_grect(win, GUIWIN_AREA_CONTENT, &mywork);
work = &mywork;
}
wind_get_grect(win->handle, WF_FIRSTXYWH, &area);
while (area.g_w && area.g_w) {
if (rc_intersect(work, &area)) {
retval = true;
}
wind_get_grect(win->handle, WF_NEXTXYWH, &area);
}
return(retval);
}
/*
void guiwin_exec_redraw(){
}
*/