/* * selection.c: Handle selections on videotext page * * $Id: selection.c,v 1.1 1997/10/22 23:46:51 mb Exp mb $ * * Copyright (c) 1997 Martin Buck * Read COPYING for more information * */ #include #include #include #include "vtx_assert.h" #include "misc.h" #include "vtxdecode.h" #include "xevents.h" #include "selection.h" static Selection_owner xvsel; static Selection_item xvsel_item; static char sel_buf[VTX_PAGESIZE + 24 + 1]; /* Add 24 chars for linefeeds, 1 for '\0' */ static void lose_proc(Selection_owner owner) { /*FIXME: Don't use globals here*/ selection_hide(&vtxwin); } static void invert_range(vtxpage_t *page, int x1, int y1, int x2, int y2, int rect) { int x, y, pos, xmin, xmax, ymin, ymax; if (rect) { xmin = MIN(x1, x2); xmax = MAX(x1, x2); ymin = MIN(y1, y2); ymax = MAX(y1, y2); for (y = ymin; y <= ymax; y++) { for (x = xmin; x <= xmax; x++) { page->attrib[y * 40 + x] ^= VTX_INVERT; } } } else { if (y1 < y2 || (y1 == y2 && x1 < x2)) { xmin = x1; ymin = y1; xmax = x2; ymax = y2; } else { xmin = x2; ymin = y2; xmax = x1; ymax = y1; } for (pos = ymin * 40 + xmin; pos <= ymax * 40 + xmax; pos++) { page->attrib[pos] ^= VTX_INVERT; } } } void selection_start(vtxpgwin_t *vtxwin, int x, int y, int rect, int expand) { selection_t *sel = &vtxwin->sel; int pos, pos0, pos1; x = LIMIT(x, 0, 39); y = LIMIT(y, 0, 23); if (!expand) { selection_hide(vtxwin); sel->disp_x[0] = sel->disp_x[1] = x; sel->disp_y[0] = sel->disp_y[1] = y; sel->expand = -1; sel->rect = rect; } else { if (sel->show) { invert_range(vtxwin->page, sel->disp_x[0], sel->disp_y[0], sel->disp_x[1], sel->disp_y[1], sel->rect); } if (!sel->rect) { pos0 = sel->sel_x[0] + sel->sel_y[0] * 40; pos1 = sel->sel_x[1] + sel->sel_y[1] * 40; pos = x + y * 40; sel->expand = (pos > (pos0 + pos1) / 2) ^ (pos0 > pos1); sel->disp_x[sel->expand] = x; sel->disp_y[sel->expand] = y; sel->disp_x[!sel->expand] = sel->sel_x[!sel->expand]; sel->disp_y[!sel->expand] = sel->sel_y[!sel->expand]; } else { sel->expand = ((x > (sel->sel_x[0] + sel->sel_x[1]) / 2) ^ (sel->sel_x[0] > sel->sel_x[1])) | (((y > (sel->sel_y[0] + sel->sel_y[1]) / 2) ^ (sel->sel_y[0] > sel->sel_y[1])) << 1); sel->disp_x[sel->expand & 1] = x; sel->disp_y[sel->expand >> 1] = y; sel->disp_x[!(sel->expand & 1)] = sel->sel_x[!(sel->expand & 1)]; sel->disp_y[!(sel->expand >> 1)] = sel->sel_y[!(sel->expand >> 1)]; } invert_range(vtxwin->page, sel->disp_x[0], sel->disp_y[0], sel->disp_x[1], sel->disp_y[1], sel->rect); x_vtx_redraw(vtxwin, 0, 0, 39, 23, FALSE); sel->show = TRUE; } sel->last_x = -1; sel->init = TRUE; } void selection_drag(vtxpgwin_t *vtxwin, int x, int y) { selection_t *sel = &vtxwin->sel; int pos, pos0, pos1, newexp; sel->drag = TRUE; x = LIMIT(x, 0, 39); y = LIMIT(y, 0, 23); if (x != sel->last_x || y != sel->last_y) { if (sel->show) { invert_range(vtxwin->page, sel->disp_x[0], sel->disp_y[0], sel->disp_x[1], sel->disp_y[1], sel->rect); } if (sel->expand < 0) { sel->disp_x[1] = x; sel->disp_y[1] = y; } else { if (!sel->rect) { pos0 = sel->sel_x[0] + sel->sel_y[0] * 40; pos1 = sel->sel_x[1] + sel->sel_y[1] * 40; pos = x + y * 40; newexp = -1; if (pos < MIN(pos0, pos1)) { newexp = pos1 < pos0; } if (pos > MAX(pos0, pos1)) { newexp = pos1 > pos0; } if (newexp >= 0 && newexp != sel->expand) { sel->disp_x[sel->expand] = sel->sel_x[sel->expand]; sel->disp_y[sel->expand] = sel->sel_y[sel->expand]; sel->expand = newexp; } sel->disp_x[sel->expand] = x; sel->disp_y[sel->expand] = y; } else { newexp = -1; if (x < MIN(sel->sel_x[0], sel->sel_x[1])) { newexp = sel->sel_x[1] < sel->sel_x[0]; } if (x > MAX(sel->sel_x[0], sel->sel_x[1])) { newexp = sel->sel_x[1] > sel->sel_x[0]; } if (newexp >= 0 && newexp != (sel->expand & 1)) { sel->disp_x[sel->expand & 1] = sel->sel_x[sel->expand & 1]; sel->expand = (sel->expand & ~1) | newexp; } sel->disp_x[sel->expand & 1] = x; newexp = -1; if (y < MIN(sel->sel_y[0], sel->sel_y[1])) { newexp = (sel->sel_y[1] < sel->sel_y[0]) << 1; } if (y > MAX(sel->sel_y[0], sel->sel_y[1])) { newexp = (sel->sel_y[1] > sel->sel_y[0]) << 1; } if (newexp >= 0 && newexp != (sel->expand & 2)) { sel->disp_y[sel->expand >> 1] = sel->sel_y[sel->expand >> 1]; sel->expand = (sel->expand & ~2) | newexp; } sel->disp_y[sel->expand >> 1] = y; } } invert_range(vtxwin->page, sel->disp_x[0], sel->disp_y[0], sel->disp_x[1], sel->disp_y[1], sel->rect); x_vtx_redraw(vtxwin, 0, 0, 39, 23, FALSE); sel->last_x = x; sel->last_y = y; } if (!sel->show && xvsel) { xv_set(xvsel, SEL_OWN, FALSE, NULL); } sel->show = TRUE; } void selection_finish(vtxpgwin_t *vtxwin) { selection_t *sel = &vtxwin->sel; int sofs; if (!sel->init) { return; } if (sel->show) { sel->sel_x[0] = sel->disp_x[0]; sel->sel_y[0] = sel->disp_y[0]; sel->sel_x[1] = sel->disp_x[1]; sel->sel_y[1] = sel->disp_y[1]; if (!xvsel) { xvsel = xv_create(vtxwin->canvas, SELECTION_OWNER, SEL_LOSE_PROC, lose_proc, NULL); xvsel_item = xv_create(xvsel, SELECTION_ITEM, NULL); } sofs = 0; if (sel->rect) { int sxmin = MIN(sel->sel_x[0], sel->sel_x[1]); int sxmax = MAX(sel->sel_x[0], sel->sel_x[1]); int symin = MIN(sel->sel_y[0], sel->sel_y[1]); int symax = MAX(sel->sel_y[0], sel->sel_y[1]); int sx, sy; for (sy = symin; sy <= symax; sy++) { for (sx = sxmin; sx <= sxmax; sx++) { if ((vtxwin->page->attrib[sy * 40 + sx] & VTX_HIDDEN) && vtxwin->hidden) { sel_buf[sofs++] = ' '; } else { sel_buf[sofs++] = vtx2iso_table[vtxwin->page->chr[sy * 40 + sx]]; } } if (symin != symax) { sel_buf[sofs++] = '\n'; } } } else { int start, end, pos; if (sel->sel_y[0] < sel->sel_y[1] || (sel->sel_y[0] == sel->sel_y[1] && sel->sel_x[0] < sel->sel_x[1])) { start = sel->sel_y[0] * 40 + sel->sel_x[0]; end = sel->sel_y[1] * 40 + sel->sel_x[1]; } else { start = sel->sel_y[1] * 40 + sel->sel_x[1]; end = sel->sel_y[0] * 40 + sel->sel_x[0]; } for (pos = start; pos <= end; pos++) { if ((vtxwin->page->attrib[pos] & VTX_HIDDEN) && vtxwin->hidden) { sel_buf[sofs++] = ' '; } else { sel_buf[sofs++] = vtx2iso_table[vtxwin->page->chr[pos]]; } if (pos % 40 == 39 && sel->sel_y[0] != sel->sel_y[1]) { sel_buf[sofs++] = '\n'; } } } sel_buf[sofs++] = '\0'; xv_set(xvsel_item, SEL_DATA, sel_buf, SEL_LENGTH, strlen(sel_buf), NULL); xv_set(xvsel, SEL_OWN, TRUE, NULL); } sel->drag = sel->init = FALSE; } void selection_hide(vtxpgwin_t *vtxwin) { selection_t *sel = &vtxwin->sel; if (!sel->show) { return; } invert_range(vtxwin->page, sel->disp_x[0], sel->disp_y[0], sel->disp_x[1], sel->disp_y[1], sel->rect); x_vtx_redraw(vtxwin, 0, 0, 39, 23, FALSE); sel->show = sel->init = sel->drag = FALSE; }