tests/xpick: tests/xpick.o libedit.a
tests/term: tests/term.o libedit.a
+%: %.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
# load generate dependencies
-include *.d lib/*.d tests/*.d tests/lib/*.d
Up Next:
-* Run commands in the background and don't block the main thread.
-* refactor selection handling to buf.c to prepare for multiple selections.
* Make Fn keys execute nth command in the tags buffers
-* 100% coverage with unit and unit-integration tests
-* Status line should omit characters from beginning of path to make file path fit
-* right click to fetch file or line
-
-Straight-up Bugs:
-
-* tab inserts dont coalesce like one would expect
+* arrow keys with selection should clear the selection instead of moving.
+* move by words is inconsistent. Example:
+ var infoId = 'readerinfo'+reader.id;
The Future:
+* refactor selection handling to buf.c to prepare for multiple selections.
+* 100% coverage with unit and unit-integration tests
+* right click to fetch file or line
+* tab inserts dont coalesce like one would expect
+* Run commands in the background and don't block the main thread.
* shortcut to repeat previous operation
* add command line flags to toggle options (Tabs, Indent, etc..)
* add command env vars to set options (Tabs, Indent, etc..)
* implement command diffing logic to optimize the undo/redo log
-
-# Mouse Chords
-
-Mouse Sequence Description
---------------------------------------------------------------------------------
-Pl Rl Null Selection
-Pl Rl Pl Rl Select by context
-Pl Rl Pl Rl Pl Rl Select big word
-Pl Pm Cut line or selection
-Pl Pr Paste
-Pm Rm Execute text
-Pm Pr Cancel the execution that would occur
-Pr Rr Search
-Pr Pm Cancel the search that would occur
+* Status line should omit characters from beginning of path to make file path fit
# Auxillary Programs
+enum {
+ MouseLeft = 1,
+ MouseMiddle = 2,
+ MouseRight = 3,
+ MouseWheelUp = 4,
+ MouseWheelDn = 5
+};
+
typedef enum {
STATUS = 0,
TAGS = 1,
View* win_view(WinRegion id);
Buf* win_buf(WinRegion id);
Sel* win_sel(WinRegion id);
-bool win_btnpressed(MouseBtn btn);
+bool win_btnpressed(int btn);
WinRegion win_getregion(void);
bool win_setregion(WinRegion id);
void win_setscroll(double offset, double visible);
void onupdate(void);
void onlayout(void);
void onscroll(double percent);
-void onmouseleft(WinRegion id, size_t count, size_t row, size_t col);
-void onmousemiddle(WinRegion id, size_t count, size_t row, size_t col);
-void onmouseright(WinRegion id, size_t count, size_t row, size_t col);
+void onmouseleft(WinRegion id, bool pressed, size_t row, size_t col);
+void onmousemiddle(WinRegion id, bool pressed, size_t row, size_t col);
+void onmouseright(WinRegion id, bool pressed, size_t row, size_t col);
-typedef enum {
- MOUSE_ACT_UP,
- MOUSE_ACT_DOWN,
- MOUSE_ACT_MOVE
-} MouseAct;
-
-typedef enum {
- MOUSE_BTN_LEFT = 0,
- MOUSE_BTN_MIDDLE = 1,
- MOUSE_BTN_RIGHT = 2,
- MOUSE_BTN_WHEELUP = 3,
- MOUSE_BTN_WHEELDOWN = 4,
- MOUSE_BTN_NONE = 5,
- MOUSE_BTN_COUNT = 6
-} MouseBtn;
-
typedef struct {
void (*redraw)(int width, int height);
void (*handle_key)(int mods, uint32_t rune);
- void (*handle_mouse)(MouseAct act, MouseBtn btn, int x, int y);
void (*shutdown)(void);
void (*set_focus)(bool focus);
+ void (*mouse_drag)(int state, int x, int y);
+ void (*mouse_btn)(int state, bool pressed, int x, int y);
uint32_t palette[16];
} XConfig;
void x11_init(XConfig* cfg);
void x11_deinit(void);
-int x11_keymods(void);
+int x11_keybtnstate(void);
bool x11_keymodsset(int mask);
void x11_window(char* name, int width, int height);
void x11_dialog(char* name, int height, int width);
#include <win.h>
#include <ctype.h>
-typedef struct {
- uint64_t time;
- uint8_t count;
- bool pressed;
- int region;
-} ButtonState;
-
-static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t ncols);
-static WinRegion getregion(size_t x, size_t y);
static void onredraw(int height, int width);
static void oninput(int mods, Rune key);
-static void onmouse(MouseAct act, MouseBtn btn, int x, int y);
-static void onwheelup(WinRegion id, size_t count, size_t row, size_t col);
-static void onwheeldn(WinRegion id, size_t count, size_t row, size_t col);
+static void onmousedrag(int state, int x, int y);
+static void onmousebtn(int btn, bool pressed, int x, int y);
+static void onwheelup(WinRegion id, bool pressed, size_t row, size_t col);
+static void onwheeldn(WinRegion id, bool pressed, size_t row, size_t col);
+static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t ncols);
+static WinRegion getregion(size_t x, size_t y);
static size_t Ruler = 0;
static double ScrollOffset = 0.0;
static XConfig Config = {
.redraw = onredraw,
.handle_key = oninput,
- .handle_mouse = onmouse,
.shutdown = onshutdown,
.set_focus = onfocus,
+ .mouse_drag = onmousedrag,
+ .mouse_btn = onmousebtn,
.palette = COLOR_PALETTE
};
-
-void (*MouseActs[MOUSE_BTN_COUNT])(WinRegion id, size_t count, size_t row, size_t col) = {
- [MOUSE_BTN_LEFT] = onmouseleft,
- [MOUSE_BTN_MIDDLE] = onmousemiddle,
- [MOUSE_BTN_RIGHT] = onmouseright,
- [MOUSE_BTN_WHEELUP] = onwheelup,
- [MOUSE_BTN_WHEELDOWN] = onwheeldn,
-};
-
static WinRegion Focused = EDIT;
static Region Regions[NREGIONS] = {0};
-static ButtonState MouseBtns[MOUSE_BTN_COUNT] = {0};
KeyBinding* Keys = NULL;
static void win_init(void (*errfn)(char*)) {
static int prev_x = 0, prev_y = 0;
int ptr_x, ptr_y;
bool changed = false;
- x11_mouse_get(&ptr_x, &ptr_y);
- if (prev_x != ptr_x || prev_y != ptr_y)
- changed = win_setregion(getregion(ptr_x, ptr_y));
- prev_x = ptr_x, prev_y = ptr_y;
+ /* dont change focus if any mouse buttons are pressed */
+ if ((x11_keybtnstate() & 0x1f00) == 0)
+ {
+ x11_mouse_get(&ptr_x, &ptr_y);
+ if (prev_x != ptr_x || prev_y != ptr_y)
+ changed = win_setregion(getregion(ptr_x, ptr_y));
+ prev_x = ptr_x, prev_y = ptr_y;
+ }
return changed;
}
Keys = bindings;
}
-bool win_btnpressed(MouseBtn btn) {
- return MouseBtns[btn].pressed;
+bool win_btnpressed(int btn) {
+ int btnmask = (1 << (btn + 7));
+ return ((x11_keybtnstate() & btnmask) == btnmask);
}
WinRegion win_getregion(void) {
}
}
-static void onclick(MouseAct act, MouseBtn btn, int x, int y) {
- WinRegion id = getregion(x, y);
- size_t row = (y-Regions[id].y) / x11_font_height(Font);
- size_t col = (x-Regions[id].x) / x11_font_width(Font);
- if (id == SCROLL) {
- id = EDIT;
- switch (btn) {
- case MOUSE_BTN_LEFT:
+static void scroll_actions(int btn, bool pressed, int x, int y) {
+ size_t row = (y-Regions[SCROLL].y) / x11_font_height(Font);
+ size_t col = (x-Regions[SCROLL].x) / x11_font_width(Font);
+ switch (btn) {
+ case MouseLeft:
+ if (pressed)
view_scroll(win_view(EDIT), -row);
- break;
- case MOUSE_BTN_MIDDLE:
+ break;
+ case MouseMiddle:
+ if (pressed)
onscroll((double)(y - Regions[SCROLL].y) /
(double)(Regions[SCROLL].height - Regions[SCROLL].y));
- break;
- case MOUSE_BTN_RIGHT:
+ break;
+ case MouseRight:
+ if (pressed)
view_scroll(win_view(EDIT), +row);
- break;
- case MOUSE_BTN_WHEELUP:
- view_scroll(win_view(id), -ScrollLines);
- break;
- case MOUSE_BTN_WHEELDOWN:
- view_scroll(win_view(id), +ScrollLines);
- break;
- default:
- break;
- }
- } else if (MouseActs[btn]) {
- MouseActs[btn](MouseBtns[btn].region, MouseBtns[btn].count, row, col);
+ break;
+ case MouseWheelUp:
+ view_scroll(win_view(EDIT), -ScrollLines);
+ break;
+ case MouseWheelDn:
+ view_scroll(win_view(EDIT), +ScrollLines);
+ break;
}
}
-static void onmouse(MouseAct act, MouseBtn btn, int x, int y) {
+static void onmousedrag(int state, int x, int y) {
WinRegion id = getregion(x, y);
size_t row = (y-Regions[id].y) / x11_font_height(Font);
size_t col = (x-Regions[id].x) / x11_font_width(Font);
- if (act == MOUSE_ACT_MOVE) {
- if (MouseBtns[MOUSE_BTN_LEFT].pressed) {
- WinRegion selid = MouseBtns[MOUSE_BTN_LEFT].region;
- if (MouseBtns[MOUSE_BTN_LEFT].count == 1) {
- view_setcursor(win_view(selid), row, col);
- MouseBtns[MOUSE_BTN_LEFT].count = 0;
- } else {
- view_selext(win_view(selid), row, col);
- }
- }
+ if (id == Focused && win_btnpressed(MouseLeft))
+ view_selext(win_view(id), row, col);
+}
+
+static void onmousebtn(int btn, bool pressed, int x, int y) {
+ WinRegion id = getregion(x, y);
+ size_t row = (y-Regions[id].y) / x11_font_height(Font);
+ size_t col = (x-Regions[id].x) / x11_font_width(Font);
+
+ if (id == SCROLL) {
+ scroll_actions(btn, pressed, x, y);
} else {
- MouseBtns[btn].pressed = (act == MOUSE_ACT_DOWN);
- if (MouseBtns[btn].pressed) {
- /* update the number of clicks and click time */
- uint32_t now = getmillis();
- uint32_t elapsed = now - MouseBtns[btn].time;
- MouseBtns[btn].time = now;
- MouseBtns[btn].region = id;
- if (elapsed <= 250)
- MouseBtns[btn].count++;
- else
- MouseBtns[btn].count = 1;
- } else if (MouseBtns[btn].count > 0) {
- onclick(act, btn, x, y);
+ switch(btn) {
+ case MouseLeft: onmouseleft(id, pressed, row, col); break;
+ case MouseMiddle: onmousemiddle(id, pressed, row, col); break;
+ case MouseRight: onmouseright(id, pressed, row, col); break;
+ case MouseWheelUp: onwheelup(id, pressed, row, col); break;
+ case MouseWheelDn: onwheeldn(id, pressed, row, col); break;
}
}
}
-static void onwheelup(WinRegion id, size_t count, size_t row, size_t col) {
+static void onwheelup(WinRegion id, bool pressed, size_t row, size_t col) {
+ if (!pressed) return;
view_scroll(win_view(id), -ScrollLines);
}
-static void onwheeldn(WinRegion id, size_t count, size_t row, size_t col) {
+static void onwheeldn(WinRegion id, bool pressed, size_t row, size_t col) {
+ if (!pressed) return;
view_scroll(win_view(id), +ScrollLines);
}
-/*****************************************************************************/
-
static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t ncols) {
XGlyphSpec specs[rlen];
size_t i = 0;
}
return NREGIONS;
}
-
GC gc;
} X;
static XConfig* Config;
-static int Mods;
+static int KeyBtnState;
static Atom SelTarget;
static struct XSel {
char* name;
SelTarget = XInternAtom(X.display, "STRING", 0);
}
-int x11_keymods(void) {
- return Mods;
+int x11_keybtnstate(void) {
+ return KeyBtnState;
}
bool x11_keymodsset(int mask) {
- return ((Mods & mask) == mask);
+ return ((KeyBtnState & mask) == mask);
}
void x11_window(char* name, int width, int height) {
static void handle_key(XEvent* event) {
uint32_t key = getkey(event);
- Mods = event->xkey.state & ModAny;
+ KeyBtnState = event->xkey.state;
if (key == RUNE_ERR) return;
- Config->handle_key(Mods, key);
+ Config->handle_key(KeyBtnState, key);
}
static void handle_mouse(XEvent* e) {
- MouseAct action;
- MouseBtn button;
int x = 0, y = 0;
if (e->type == MotionNotify) {
- action = MOUSE_ACT_MOVE;
- button = MOUSE_BTN_LEFT;
+ KeyBtnState = e->xmotion.state;
x = e->xmotion.x;
y = e->xmotion.y;
+ Config->mouse_drag(KeyBtnState, x, y);
} else {
- Mods = e->xbutton.state & ModAny;
- action = (e->type == ButtonPress ? MOUSE_ACT_DOWN : MOUSE_ACT_UP);
- /* set the button id */
- switch (e->xbutton.button) {
- case Button1: button = MOUSE_BTN_LEFT; break;
- case Button2: button = MOUSE_BTN_MIDDLE; break;
- case Button3: button = MOUSE_BTN_RIGHT; break;
- case Button4: button = MOUSE_BTN_WHEELUP; break;
- case Button5: button = MOUSE_BTN_WHEELDOWN; break;
- default: button = MOUSE_BTN_NONE; break;
- }
+ KeyBtnState = e->xbutton.state;
x = e->xbutton.x;
y = e->xbutton.y;
+ Config->mouse_btn(e->xbutton.button, (e->type == ButtonPress), x, y);
}
- /* pass the data to the app */
- Config->handle_mouse(action, button, x, y);
}
static void set_focus(bool focused) {
#include <ctype.h>
#include <win.h>
-void onmouseleft(WinRegion id, size_t count, size_t row, size_t col) {
-
+void onmouseleft(WinRegion id, bool pressed, size_t row, size_t col) {
}
-void onmousemiddle(WinRegion id, size_t count, size_t row, size_t col) {
-
+void onmousemiddle(WinRegion id, bool pressed, size_t row, size_t col) {
}
-void onmouseright(WinRegion id, size_t count, size_t row, size_t col) {
-
+void onmouseright(WinRegion id, bool pressed, size_t row, size_t col) {
}
void onscroll(double percent) {
-
}
void onfocus(bool focused) {
}
void onerror(char* msg) {
-
}
#ifndef TEST
/* Mouse Handling
******************************************************************************/
-void onmouseleft(WinRegion id, size_t count, size_t row, size_t col) {
+void onmouseleft(WinRegion id, bool pressed, size_t row, size_t col) {
+ static int count = 0;
+ static uint64_t before = 0;
+ if (!pressed) return;
+ uint64_t now = getmillis();
+ count = ((now-before) <= 250 ? count+1 : 1);
+ before = now;
+
if (count == 1) {
if (x11_keymodsset(ModShift))
view_selext(win_view(id), row, col);
}
}
-void onmousemiddle(WinRegion id, size_t count, size_t row, size_t col) {
- if (win_btnpressed(MOUSE_BTN_LEFT)) {
+void onmousemiddle(WinRegion id, bool pressed, size_t row, size_t col) {
+ if (pressed) return;
+ if (win_btnpressed(MouseLeft)) {
cut();
} else {
char* str = view_fetch(win_view(id), row, col);
}
}
-void onmouseright(WinRegion id, size_t count, size_t row, size_t col) {
- if (win_btnpressed(MOUSE_BTN_LEFT)) {
+void onmouseright(WinRegion id, bool pressed, size_t row, size_t col) {
+ if (pressed) return;
+ if (win_btnpressed(MouseLeft)) {
paste();
} else {
SearchDir *= (x11_keymodsset(ModShift) ? -1 : +1);
vec_sort(&Choices, by_score);
}
-void onmouseleft(WinRegion id, size_t count, size_t row, size_t col) {
+void onmouseleft(WinRegion id, bool pressed, size_t row, size_t col) {
}
-void onmousemiddle(WinRegion id, size_t count, size_t row, size_t col) {
+void onmousemiddle(WinRegion id, bool pressed, size_t row, size_t col) {
}
-void onmouseright(WinRegion id, size_t count, size_t row, size_t col) {
+void onmouseright(WinRegion id, bool pressed, size_t row, size_t col) {
}
void onscroll(double percent) {