/* * Zoom accessory * */ #include #include #include #include #define elements(p) (p).g_x, (p).g_y, (p).g_w, (p).g_h #define pointers(p) &(p).g_x, &(p).g_y, &(p).g_w, &(p).g_h #define clip(lower, val, upper) min((upper), max((lower), (val))) #define WF_PARTS (NAME+CLOSE+MOVE) typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned long ulong; #ifdef LATTICE extern long _STACK = 2048; #endif /* * Assembler functions to zoom up a single screen line and to blit the zoomed * buffer onto the screen *fast* * */ extern void zoomLine(void *, void *, short, short); extern void qblit(void *, void *, short); #ifdef ACCorPRG extern int _XMODE; /* Lattice startup stub variable: 2 = DA */ #endif short handle; /* VDI handle */ short m[8]; /* AES message buffer */ short err; /* Accessory installed? */ uchar zoomed[128][16]; /* Array of zoomed pixels */ struct la_data *data; /* Line A data */ uchar *display; /* Pointer to screen memory */ char *title = " Zoom "; /* The DA title as well as the window title */ MFDB zoomarea = {zoomed, 128, 128, 8, 0, 1, 0, 0, 0}; MFDB screen; /* * Function: Convert a window work area so that it lies on a word boundary * * Parameters: Original work area, result work area * * Returns: None * */ void work2work(GRECT *work1, GRECT *work2) { work2->g_x = (work1->g_x + 15) / 16; work2->g_x = work2->g_x * 16 - 1; work2->g_y = work1->g_y; work2->g_w = work1->g_w; work2->g_h = work1->g_h; } /* * Function: Convert a window border to a word-aligned work area * * Parameters: Border area, result work area * * Returns: None * */ void curr2work(GRECT *curr, GRECT *work) { GRECT temp; wind_calc(WC_WORK, WF_PARTS, elements(*curr), pointers(temp)); work2work(&temp, work); } /* * Function: Convert a window border area so that it lies on screen and has * a word-aligned work area * * Parameters: Original border area, result border area * * Returns: None * */ void curr2curr(GRECT *curr1, GRECT *curr2) { GRECT temp; wind_get(0, WF_WORKXYWH, pointers(temp)); curr1->g_x = min(curr1->g_x, temp.g_x + temp.g_w - curr1->g_w - 2); curr1->g_y = min(curr1->g_y, temp.g_y + temp.g_h - curr1->g_h - 2); curr2work(curr1, &temp); wind_calc(WC_BORDER, WF_PARTS, elements(temp), pointers(*curr2)); } /* * Function: Produce a zoomed display in the global zoomed array (assuming * a THIN_CROSS mouse, the area is offset by the hot-spot of 7,7) * * Parameters: Mouse x and y coordinates of top-left corner of area * * Returns: None * */ void zoom(short x, short y) { uchar *scr; x = clip(0, x - 7, data->ld_vwrap * 8 - 16); y = clip(0, y - 7, V_Y_MAX - 16); scr = display + 2 * (x / 16); scr += (long)y * data->ld_vwrap; graf_mouse(M_OFF, NULL); zoomLine(scr, zoomed, data->ld_vwrap, x % 16); graf_mouse(M_ON, NULL); } /* * Function: Function called by wind_redraw to redraw the window from the * zoomed buffer. Also, a white pixel border is drawn on 2 sides * * Parameters: Window handle, area to redraw * * Returns: 1 (continue redrawing) * */ int redraw(int win, GRECT *p) { GRECT work; short pxy[8]; pxy[0] = p->g_x; pxy[1] = p->g_y; pxy[2] = p->g_x + p->g_w - 1; pxy[3] = p->g_y + p->g_h - 1; vs_clip(handle, 1, pxy); wind_get(win, WF_WORKXYWH, pointers(work)); pxy[0] = work.g_x + work.g_w - 1; pxy[1] = work.g_y; pxy[2] = work.g_x; pxy[3] = work.g_y; pxy[4] = work.g_x; pxy[5] = work.g_y + work.g_h - 1; vsl_color(handle, WHITE); v_pline(handle, 3, pxy); /* Draw a pixel border on the top & left */ vs_clip(handle, 0, pxy); work.g_x++; work.g_y++; work.g_w--; work.g_h--; rc_intersect(&work, p); pxy[0] = p->g_x - work.g_x; pxy[1] = p->g_y - work.g_y; pxy[2] = pxy[0] + p->g_w - 1; pxy[3] = pxy[1] + p->g_h - 1; pxy[4] = p->g_x; pxy[5] = p->g_y; pxy[6] = p->g_x + p->g_w - 1; pxy[7] = p->g_y + p->g_h - 1; vro_cpyfm(handle, S_ONLY, pxy, &zoomarea, &screen); return 1; } #ifndef LATTICE /* * Function: Manage window redraws by calling a supplied function for * each valid screen rectangle * From the Lattice C Atari Library Manual pp73-74 * * Parameters: Window handle, redraw area, redrawing function * * Returns: 1 if OK, 0 otherwise * */ int wind_redraw(int win, GRECT *area, int (*redraw)(int, GRECT *)) { GRECT box; int ok = 1; graf_mouse(M_OFF, NULL); wind_update(BEG_UPDATE); wind_get(win, WF_FIRSTXYWH, pointers(box)); while (box.g_w && box.g_h) { if (rc_intersect(area, &box)) if (!(ok = redraw(win, &box))) break; wind_get(win, WF_NEXTXYWH, pointers(box)); } wind_update(END_UPDATE); graf_mouse(M_ON, NULL); return ok; } #endif /* * Function: Handle the opened zoom window * * Parameters: None * * Returns: None * */ void doZoom(void) { GRECT work = {127, 127, 129, 129}; GRECT curr; uchar *scr; short win; short x, y, junk; short ev; short top; int done = 0; wind_calc(WC_BORDER, WF_PARTS, elements(work), pointers(curr)); win = wind_create(WF_PARTS, elements(curr)); if (win < 0) return; wind_title(win, title + 1); wind_open(win, elements(curr)); graf_mkstate(&x, &y, &junk, &junk); zoom(x, y); graf_mouse(THIN_CROSS, NULL); do { ev = evnt_multi(MU_M1 | MU_MESAG, 0, 0, 0, 1, x, y, 1, 1, 0, 0, 0, 0, 0, m, 0, 0, &x, &y, &junk, &junk, &junk, &junk); wind_update(BEG_UPDATE); wind_get(win, WF_TOP, &top, &junk, &junk, &junk); /* * It IS possible to get MU_M1 events if the window is NOT topped!! * */ if (top == win && (ev & MU_M1)) { zoom(x, y); scr = display + (work.g_x + 1) / 8; scr += (long)(work.g_y + 1) * data->ld_vwrap; graf_mouse(M_OFF, NULL); qblit(scr, zoomed, data->ld_vwrap); graf_mouse(M_ON, NULL); } if (ev & MU_MESAG) switch (m[0]) { case WM_CLOSED: wind_close(win); wind_delete(win); /* Fall through */ case AC_CLOSE: done = 1; break; case AC_OPEN: wind_set(win, WF_TOP); break; case WM_TOPPED: if (m[3] == win) { wind_set(win, WF_TOP); graf_mouse(THIN_CROSS, NULL); } break; case WM_REDRAW: wind_redraw(win, (GRECT *)&m[4], redraw); break; case WM_MOVED: curr2curr((GRECT *)&m[4], &curr); wind_set(win, WF_CURRXYWH, elements(curr)); wind_get(win, WF_WORKXYWH, pointers(work)); break; default: break; } wind_update(END_UPDATE); } while (!done); graf_mouse(ARROW, NULL); } /* * Function: Initialise GEM, install as a DA, get screen address. * * Parameters: None * * Returns: None (sets err global) * */ void init(void) { short workin[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}; short workout[57]; short junk; short id; err = 0; data = linea0(); if (data->ld_vplanes != 1) err = -1; display = (uchar *)Logbase(); id = appl_init(); #ifdef ACCorPRG if (_XMODE == 2) #endif err = menu_register(id, title); #ifdef ACCorPRG else err = 0; #endif screen.fd_addr = NULL; handle = graf_handle(&junk, &junk, &junk, &junk); v_opnvwk(workin, &handle, workout); } /* * Function: Main program * * Parameters: None * * Returns: None (never returns if run as an accessory) * */ void main(void) { init(); #ifdef ACCorPRG if (_XMODE == 2) { #endif if (err == -1) Cconws("Error installing \033pZoomAcc\033q!\r\n"); for (;;) { evnt_mesag(m); if (err != -1 && m[0] == AC_OPEN) doZoom(); } #ifdef ACCorPRG } else { doZoom(); v_clsvwk(handle); appl_exit(); } #endif } /* End of zoomacc.c */