void on_double_click(void) { MARK save; save = DOT; TRACE(("MOUSE double-click DOT %d.%d\n", line_no(curbp, DOT.l), DOT.o)); sel_release(); if (!is_at_end_of_line(DOT) && !isSpace(CharAtDot())) { while (DOT.o > 0) { DOT.o -= BytesBefore(DOT.l, DOT.o); if (isSpace(CharAtDot())) { DOT.o += BytesAt(DOT.l, DOT.o); break; } } sel_begin(); MK = DOT; while (!is_at_end_of_line(DOT)) { DOT.o += BytesAt(DOT.l, DOT.o); if (is_at_end_of_line(DOT) || isSpace(CharAtDot())) { DOT.o -= BytesBefore(DOT.l, DOT.o); break; } } sel_extend(FALSE, TRUE); } DOT = save; update(TRUE); }
/* * FUNCTION * mousemove(int *sel_pending, * POINT *first, * POINT *current, * MARK *lmbdn_mark, * int rect_rgn) * * sel_pending - Boolean, T -> client has recorded a left mouse button (LMB) * click, and so, a selection is pending. * * first - editor row/col coordinates where LMB was initially recorded. * * latest - during the mouse move, assuming the LMB is still down, * "latest" tracks the cursor position wrt window resizing * operations (via a modeline drag). * * current - current cursor row/col coordiantes. * * lmbdn_mark - editor MARK when "LMB down" was initially recorded. * * rect_rgn - Boolean, T -> user wants rectangular region selection. * * DESCRIPTION * Using several state variables, this function handles all the semantics * of a left mouse button "MOVE" event. The semantics are as follows: * * 1) This function will not be called unless the LMB is down and the * cursor is not being used to drage the mode line (enforced by caller). * 2) a LMB move within the current editor window selects a region of text. * Later, when the user releases the LMB, that text is yanked to the * unnamed register (the yank code is not handled in this function). * * RETURNS * None */ static void mousemove(int *sel_pending, COORD * first, COORD * current, MARK *lmbdn_mark, int rect_rgn) { int dummy; if (WaitForSingleObject(hAsMutex, AS_TMOUT) == WAIT_OBJECT_0) { if (*sel_pending) { /* * Selection pending. If the mouse has moved at least one char, * start a selection. */ if (MouseClickSetPos(current, &dummy)) { /* ignore mouse jitter */ if (current->X != first->X || current->Y != first->Y) { *sel_pending = FALSE; DOT = *lmbdn_mark; (void) sel_begin(); (void) update(TRUE); } else { (void) ReleaseMutex(hAsMutex); return; } } } if (mouse_wp != row2window(current->Y)) { /* * mouse moved into a different editor window or row2window() * returned a NULL ptr. */ (void) ReleaseMutex(hAsMutex); return; } if (!setcursor(current->Y, current->X)) { (void) ReleaseMutex(hAsMutex); return; } if (rect_rgn) (void) sel_setshape(rgn_RECTANGLE); if (sel_extend(TRUE, TRUE)) (void) update(TRUE); (void) ReleaseMutex(hAsMutex); } /* * Else either the worker thread abandonded the mutex (not possible as * currently coded) or timed out. If the latter, something is * hung--don't do anything. */ }
void on_triple_click(void) { MARK save; save = DOT; TRACE(("MOUSE triple-click DOT %d.%d\n", line_no(curbp, DOT.l), DOT.o)); sel_release(); gotobol(FALSE, 1); sel_begin(); MK = DOT; gotoeol(FALSE, 1); sel_extend(FALSE, TRUE); DOT = save; update(TRUE); }
/* select all text in curbp and yank to unnamed register */ int sel_all(int f GCC_UNUSED, int n GCC_UNUSED) { int rc; MARK savedot; savedot = DOT; gotobob(0, 0); sel_begin(); gotoeob(0, 0); gotoeol(0, 0); (void) sel_setshape(rgn_EXACT); rc = sel_extend(TRUE, TRUE); DOT = savedot; if (rc) sel_yank(0); return (rc); }
int multimotion(int f, int n) { const CMDFUNC *cfp; int status, c, waserr; int pasting; REGIONSHAPE shape; MARK savedot; MARK savemark; MARK realdot; BUFFER *origbp = curbp; static int wassweephack = FALSE; /* Use the repeat-count as a shortcut to specify the type of selection. * I'd use int-casts of the enum value, but declaring enums with * specific values isn't 100% portable. */ n = need_at_least(f, n, 1); if (n == 3) regionshape = rgn_RECTANGLE; else if (n == 2) regionshape = rgn_FULLLINE; else regionshape = rgn_EXACT; shape = regionshape; sweephack = FALSE; savedot = DOT; switch (doingsweep) { case TRUE: /* the same command terminates as starts the sweep */ if (doingsweep) { do_sweep(FALSE); } mlforce("[Sweeping: Completed]"); regionshape = shape; /* since the terminating 'q' is executed as a motion, we have now lost the value of sweephack we were interested in, the one that tells us to include DOT.o in the selection. so we preserved it in wassweephack, and restore it here. */ if (wassweephack) sweephack = wassweephack; return TRUE; case SORTOFTRUE: if (doingsweep != TRUE) { do_sweep(TRUE); } sweepmsg("Begin cursor sweep..."); sel_extend(TRUE, (regionshape != rgn_RECTANGLE && sweephack)); savedot = MK; TRACE(("MOUSE BEGIN DOT: %d.%d MK %d.%d\n", line_no(curbp, DOT.l), DOT.o, line_no(curbp, MK.l), MK.o)); break; case FALSE: if (doingsweep != TRUE) { do_sweep(TRUE); } sweepmsg("Begin cursor sweep..."); (void) sel_begin(); (void) sel_setshape(shape); break; } waserr = TRUE; /* to force message "state-machine" */ realdot = DOT; pasting = FALSE; while (doingsweep) { /* Fix up the screen */ (void) update(FALSE); /* get the next command from the keyboard */ c = kbd_seq(); if (ABORTED(c) || curbp != origbp) { return release_selection(FALSE); } f = FALSE; n = 1; do_repeats(&c, &f, &n); /* and execute the command */ cfp = SelectKeyBinding(c); if ((cfp != NULL) && ((cfp->c_flags & (GOAL | MOTION)) != 0)) { MARK testdot; wassweephack = sweephack; sweephack = FALSE; TRACE(("MOUSE TEST DOT: %d.%d MK %d.%d\n", line_no(curbp, DOT.l), DOT.o, line_no(curbp, MK.l), MK.o)); testdot = DOT; status = execute(cfp, f, n); switch (status) { case SEL_RELEASE: TRACE(("MOUSE SEL_RELEASE %d.%d\n", line_no(curbp, DOT.l), DOT.o)); return release_selection(TRUE); case SEL_PASTE: pasting = TRUE; /* FALLTHRU */ case SEL_FINISH: do_sweep(FALSE); break; case SORTOFTRUE: TRACE(("MOUSE selection pending %d.%d -> %d.%d\n", line_no(curbp, realdot.l), realdot.o, line_no(curbp, testdot.l), testdot.o)); realdot = testdot; break; case SEL_BEGIN: savedot = MK; TRACE(("MOUSE SEL_BEGIN...\n")); /*FALLTHRU */ case SEL_EXTEND: TRACE(("MOUSE SEL_EXTEND from %d.%d to %d.%d\n", line_no(curbp, savedot.l), savedot.o, line_no(curbp, DOT.l), DOT.o)); /*FALLTHRU */ case TRUE: if (waserr && doingsweep) { sweepmsg("Sweeping..."); waserr = FALSE; } realdot = DOT; DOT = savedot; (void) sel_begin(); DOT = realdot; TRACE(("MOUSE LOOP save: %d.%d real %d.%d, mark %d.%d\n", line_no(curbp, savedot.l), savedot.o, line_no(curbp, realdot.l), realdot.o, line_no(curbp, MK.l), MK.o)); (void) sel_setshape(shape); /* we sometimes want to include DOT.o in the selection (unless it's a rectangle, in which case it's taken care of elsewhere) */ sel_extend(TRUE, (regionshape != rgn_RECTANGLE && sweephack)); break; default: sweepmsg("Sweeping: Motion failed."); waserr = TRUE; break; } } else { sweepmsg("Sweeping: Only motions permitted"); waserr = TRUE; } } regionshape = shape; /* if sweephack is set here, it's because the last motion had it set */ if (doingopcmd) pre_op_dot = savedot; savedot = DOT; savemark = MK; DOT = realdot; TRACE(("MOUSE SAVE DOT: %d.%d MK %d.%d\n", line_no(curbp, DOT.l), DOT.o, line_no(curbp, MK.l), MK.o)); if ((regionshape != rgn_RECTANGLE) && sweephack) { if (dot_vs_mark() < 0) MK.o += BytesAt(MK.l, MK.o); else DOT.o += BytesAt(DOT.l, DOT.o); } status = yankregion(); DOT = savedot; MK = savemark; sweephack = wassweephack = FALSE; if (status == TRUE && pasting) status = SEL_PASTE; return status; }
/* * On button press, we get an explicit number (1,2,3), and on release we don't * really know which button, but assume it is the last-pressed button. */ int on_mouse_click(int button, int y, int x) { static int first_x, first_y, pending; WINDOW *this_wp, *that_wp; int status; if (button > 0) { if (valid_window(this_wp = row2window(y)) && (y != mode_row(this_wp))) { /* * If we get a click on the "<" marking the left side * of a shifted window, force the screen right. This * makes it more consistent if there's a tab. */ if (w_val(this_wp, WVAL_SIDEWAYS) && x == 0) { mvleftwind(FALSE, 1); } if (!doingsweep) { if (button == BTN_EXTEND) { first_x = offs2col(this_wp, this_wp->w_dot.l, this_wp->w_dot.o); first_y = line_no(this_wp->w_bufp, this_wp->w_dot.l) - line_no(this_wp->w_bufp, this_wp->w_line.l); } else { first_x = x; first_y = y; } } status = setcursor(y, x); /* * Check for button1-down while we're in multimotion * sweep, so we can suppress highlighting extension. */ if (button != BTN_EXTEND && status == TRUE && doingsweep) { status = SORTOFTRUE; if (button == BTN_BEGIN) { first_x = x; first_y = y; } } } else { /* pressed button on modeline */ status = SORTOFTRUE; first_x = x; first_y = y; } pending = button; } else if (pending) { button = pending; pending = FALSE; this_wp = row2window(y); that_wp = row2window(first_y); if (this_wp == 0 || that_wp == 0 || reading_msg_line) { TRACE(("MOUSE cannot move msg-line\n")); status = FALSE; } else if (insertmode && (this_wp != curwp || that_wp != curwp)) { TRACE(("MOUSE cannot move from window while inserting\n")); kbd_alarm(); status = ABORT; } else if (first_y == mode_row(that_wp)) { /* drag modeline? */ if (first_y == y) { sel_release(); status = SEL_RELEASE; } else { WINDOW *save_wp = curwp; TRACE(("MOUSE dragging modeline\n")); set_curwp(that_wp); status = shrinkwind(FALSE, first_y - y); set_curwp(save_wp); } } else if (y != first_y || x != first_x) { /* drag selection */ if (button == BTN_PASTE) { (void) setcursor(y, x); status = paste_selection(); } else if (doingsweep) { switch (button) { case BTN_BEGIN: (void) release_selection(TRUE); status = setcursor(first_y, first_x); if (status == TRUE) { MK = DOT; status = SEL_BEGIN; TRACE(("MOUSE setting SEL_BEGIN MK %d.%d\n", line_no(curbp, MK.l), MK.o)); } break; default: (void) setcursor(y, x); status = SEL_EXTEND; TRACE(("MOUSE setting SEL_EXTEND DOT %d.%d MK %d.%d\n", line_no(curbp, MK.l), MK.o, line_no(curbp, DOT.l), DOT.o)); break; } } else { TRACE(("MOUSE begin multimotion on button%d-up\n", button)); if (button == BTN_EXTEND) { (void) setcursor(y, x); y = first_y; x = first_x; } do_sweep(SORTOFTRUE); (void) sel_begin(); (void) sel_setshape(rgn_EXACT); (void) setcursor(y, x); status = multimotion(TRUE, 1); TRACE(("MOUSE end multimotion after button%d-up\n", button)); if (status == SEL_PASTE) status = paste_selection(); } } else { /* position the cursor */ TRACE(("MOUSE button %d position cursor\n", button)); (void) setcursor(y, x); switch (button) { case BTN_BEGIN: status = SEL_FINISH; break; case BTN_PASTE: status = paste_selection(); break; default: status = release_selection(TRUE); break; } } } else { TRACE(("MOUSE ignored (illegal state)\n")); status = FALSE; } if (status == TRUE || status >= SORTOFTRUE) (void) update(TRUE); TRACE(("MOUSE status:%d\n", status)); return status; }