Mouse rewrite
This commit is contained in:
@@ -85,18 +85,29 @@ Caret MakeCaret(Int front, Int back) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Caret ChangeBack(Caret caret, Int back) {
|
Caret SetBack(Caret caret, Int back) {
|
||||||
Int front = GetFront(caret);
|
Int front = GetFront(caret);
|
||||||
Caret result = MakeCaret(front, back);
|
Caret result = MakeCaret(front, back);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Caret ChangeFront(Caret caret, Int front) {
|
Caret SetFront(Caret caret, Int front) {
|
||||||
Int back = GetBack(caret);
|
Int back = GetBack(caret);
|
||||||
Caret result = MakeCaret(front, back);
|
Caret result = MakeCaret(front, back);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Caret SetFrontWithAnchor(Caret caret, Range anchor, Int p) {
|
||||||
|
if (anchor.min > p) {
|
||||||
|
caret = MakeCaret(p, anchor.max);
|
||||||
|
} else if (anchor.max < p) {
|
||||||
|
caret = MakeCaret(p, anchor.min);
|
||||||
|
} else {
|
||||||
|
caret = MakeCaret(anchor.max, anchor.min);
|
||||||
|
}
|
||||||
|
return caret;
|
||||||
|
}
|
||||||
|
|
||||||
bool InBounds(const Buffer &buffer, Int pos) {
|
bool InBounds(const Buffer &buffer, Int pos) {
|
||||||
bool result = pos >= 0 && pos < buffer.len;
|
bool result = pos >= 0 && pos < buffer.len;
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ bool SHIFT_PRESSED = true;
|
|||||||
Vec2I { (Int) event.xmouse, (Int)event.ymouse }
|
Vec2I { (Int) event.xmouse, (Int)event.ymouse }
|
||||||
#define Mouse(x) (event.kind == EVENT_MOUSE_##x)
|
#define Mouse(x) (event.kind == EVENT_MOUSE_##x)
|
||||||
#define MousePress() (Mouse(LEFT) || Mouse(RIGHT) || Mouse(MIDDLE))
|
#define MousePress() (Mouse(LEFT) || Mouse(RIGHT) || Mouse(MIDDLE))
|
||||||
|
#define MouseUp() (Mouse(LEFT_UP) || Mouse(RIGHT_UP) || Mouse(MIDDLE_UP))
|
||||||
|
|
||||||
void ToggleFullscreen() {
|
void ToggleFullscreen() {
|
||||||
if (IsInFullscreen) {
|
if (IsInFullscreen) {
|
||||||
@@ -78,53 +79,240 @@ void ToggleFullscreen() {
|
|||||||
IsInFullscreen = !IsInFullscreen;
|
IsInFullscreen = !IsInFullscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GotoCrumb {
|
||||||
|
BufferID buffer_id;
|
||||||
|
Caret caret;
|
||||||
|
};
|
||||||
|
Array<GotoCrumb> GotoCrumbs;
|
||||||
|
|
||||||
|
void CheckpointBeforeGoto() {
|
||||||
|
Window *window = GetWindow(GetLastActiveWindow());
|
||||||
|
View *view = GetView(window->active_view);
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
Add(&GotoCrumbs, {buffer->id, view->carets[0]});
|
||||||
|
}
|
||||||
|
|
||||||
|
void GoBackToLastCrumb() {
|
||||||
|
Window *window = GetWindow(ActiveWindow);
|
||||||
|
if (GotoCrumbs.len <= 0) return;
|
||||||
|
GotoCrumb c = Pop(&GotoCrumbs);
|
||||||
|
Buffer *buffer = GetBuffer(c.buffer_id);
|
||||||
|
View *view = WindowOpenBufferView(window, buffer->name);
|
||||||
|
view->carets[0] = c.caret;
|
||||||
|
UpdateScroll(window, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int ScreenSpaceToBufferPos(Window *window, View *view, Buffer *buffer, Vec2I mouse) {
|
||||||
|
Vec2I mworld = mouse - window->document_rect.min + view->scroll;
|
||||||
|
Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing};
|
||||||
|
XY xy = {(Int)(pos.x), (Int)(pos.y)};
|
||||||
|
Int result = XYToPosWithoutNL(*buffer, xy);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int ScreenSpaceToBufferPosErrorOutOfBounds(Window *window, View *view, Buffer *buffer, Vec2I mouse) {
|
||||||
|
Vec2I mworld = mouse - window->document_rect.min + view->scroll;
|
||||||
|
Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing};
|
||||||
|
XY xy = {(Int)(pos.x), (Int)(pos.y)};
|
||||||
|
Int result = XYToPosErrorOutOfBounds(*buffer, xy);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool GlobalCommand(Event event) {
|
bool GlobalCommand(Event event) {
|
||||||
ProfileFunction();
|
ProfileFunction();
|
||||||
bool run_window_command = true;
|
bool run_window_command = true;
|
||||||
{
|
|
||||||
Vec2I mouse = MouseVec2I();
|
|
||||||
Window *window = GetActiveWindow();
|
|
||||||
View *view = GetView(window->active_view);
|
|
||||||
bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect);
|
|
||||||
bool mouse_in_total = CheckCollisionPointRec(mouse, window->total_rect);
|
|
||||||
bool mouse_in_line_numbers = CheckCollisionPointRec(mouse, window->line_numbers_rect);
|
|
||||||
bool mouse_in_scrollbar = CheckCollisionPointRec(mouse, window->scrollbar_rect);
|
|
||||||
window->mouse_in_scrollbar = mouse_in_scrollbar;
|
|
||||||
|
|
||||||
static SDL_Cursor *SDL_MouseCursor;
|
//
|
||||||
if (SDL_MouseCursor) SDL_DestroyCursor(SDL_MouseCursor);
|
// Window cursor setting
|
||||||
|
//
|
||||||
if (window->mouse_selecting || mouse_in_document) {
|
|
||||||
SDL_MouseCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT);
|
|
||||||
SDL_SetCursor(SDL_MouseCursor);
|
|
||||||
} else if (mouse_in_scrollbar || window->mouse_selecting_scrollbar || mouse_in_line_numbers) {
|
|
||||||
SDL_MouseCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
|
||||||
SDL_SetCursor(SDL_MouseCursor);
|
|
||||||
} else {
|
|
||||||
SDL_MouseCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER);
|
|
||||||
SDL_SetCursor(SDL_MouseCursor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MousePress()) {
|
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
Array<Int> order = GetWindowZOrder(scratch);
|
Array<Int> order = GetWindowZOrder(scratch);
|
||||||
Vec2I mouse = MouseVec2I();
|
{
|
||||||
|
static SDL_Cursor *SDL_MouseCursor;
|
||||||
|
if (SDL_MouseCursor) {
|
||||||
|
SDL_DestroyCursor(SDL_MouseCursor);
|
||||||
|
SDL_MouseCursor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2I mouse = MouseVec2I();
|
||||||
For(order) {
|
For(order) {
|
||||||
Window *window = &Windows[it];
|
Window *window = &Windows[it];
|
||||||
if (!window->visible) continue;
|
if (!window->visible) continue;
|
||||||
bool mouse_in_window = CheckCollisionPointRec(mouse, window->total_rect);
|
bool mouse_in_total = CheckCollisionPointRec(mouse, window->total_rect);
|
||||||
if (mouse_in_window) {
|
bool mouse_in_scrollbar = CheckCollisionPointRec(mouse, window->scrollbar_rect);
|
||||||
|
|
||||||
|
if (!DocumentSelected && (mouse_in_scrollbar || ScrollbarSelected)) {
|
||||||
|
SDL_MouseCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
||||||
|
SDL_SetCursor(SDL_MouseCursor);
|
||||||
|
break;
|
||||||
|
} else if (mouse_in_total || DocumentSelected) {
|
||||||
|
SDL_MouseCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT);
|
||||||
|
SDL_SetCursor(SDL_MouseCursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SDL_MouseCursor) {
|
||||||
|
SDL_MouseCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
||||||
|
SDL_SetCursor(SDL_MouseCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle selected window scrollbar
|
||||||
|
// @note: the order here assumes that we won't run this code on the
|
||||||
|
// same event as the scroll was pressed
|
||||||
|
if (ScrollbarSelected && Mouse(LEFT_UP)) {
|
||||||
|
Assert(DocumentSelected == NULL);
|
||||||
|
ScrollbarSelected = NULL;
|
||||||
|
} else if (ScrollbarSelected) {
|
||||||
|
Assert(DocumentSelected == NULL);
|
||||||
|
Window *window = ScrollbarSelected;
|
||||||
|
View *view = GetView(window->active_view);
|
||||||
|
Vec2 mouse_vec2 = MouseVec2();
|
||||||
|
Scroller s = ComputeScrollerRect(window);
|
||||||
|
double size_y = (double)GetSize(window->scrollbar_rect).y;
|
||||||
|
double p = mouse_vec2.y - window->scrollbar_rect.min.y;
|
||||||
|
double v = p / size_y;
|
||||||
|
v = v + (window->mouse_scroller_offset);
|
||||||
|
view->scroll.y = (Int)(v * (double)s.line_count * (double)FontLineSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DocumentSelected && MouseUp()) {
|
||||||
|
Assert(ScrollbarSelected == NULL);
|
||||||
|
DocumentSelected = NULL;
|
||||||
|
} else if (DocumentSelected) {
|
||||||
|
Assert(ScrollbarSelected == NULL);
|
||||||
|
Window *window = DocumentSelected;
|
||||||
|
View *view = GetView(window->active_view);
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
|
||||||
|
Vec2I mouse = MouseVec2I();
|
||||||
|
Int p = ScreenSpaceToBufferPos(window, view, buffer, mouse);
|
||||||
|
|
||||||
|
Caret &caret = view->carets[0];
|
||||||
|
caret = SetFrontWithAnchor(caret, DocumentRangeAnchor, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set active window on click
|
||||||
|
if (MousePress()) {
|
||||||
|
Vec2I mouse = MouseVec2I();
|
||||||
|
For(order) {
|
||||||
|
Window *window = &Windows[it];
|
||||||
|
if (!window->visible) continue;
|
||||||
|
bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect);
|
||||||
|
if (mouse_in_document) {
|
||||||
SetActiveWindow(window->id);
|
SetActiveWindow(window->id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// underline
|
||||||
|
if (event.ctrl) {
|
||||||
|
Vec2I mouse = MouseVec2I();
|
||||||
|
For(order) {
|
||||||
|
Window *window = &Windows[it];
|
||||||
|
if (!window->visible) continue;
|
||||||
|
bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect);
|
||||||
|
if (mouse_in_document) {
|
||||||
|
View *view = GetView(window->active_view);
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
Int p = ScreenSpaceToBufferPosErrorOutOfBounds(window, view, buffer, mouse);
|
||||||
|
if (p != -1) {
|
||||||
|
view->underline_pos[view->underline_count++] = p;
|
||||||
|
Assert(view->underline_count <= 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.ctrl && Mouse(RIGHT)) {
|
||||||
|
GoBackToLastCrumb();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo: maybe move some of this stuff to window command ???
|
||||||
|
if (event.ctrl && Mouse(LEFT)) {
|
||||||
|
Vec2I mouse = MouseVec2I();
|
||||||
|
Window *window = GetActiveWindow();
|
||||||
|
|
||||||
|
bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect);
|
||||||
|
if (mouse_in_document) {
|
||||||
|
View *view = GetView(window->active_view);
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
Int p = ScreenSpaceToBufferPosErrorOutOfBounds(window, view, buffer, mouse);
|
||||||
|
if (p != -1) {
|
||||||
|
Range enclose = EncloseLoadWord(buffer, p);
|
||||||
|
String16 string = GetString(*buffer, enclose);
|
||||||
|
Open(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Mouse(LEFT)) {
|
||||||
|
Vec2I mouse = MouseVec2I();
|
||||||
|
{
|
||||||
|
Assert(ScrollbarSelected == NULL);
|
||||||
|
Assert(DocumentSelected == NULL);
|
||||||
|
|
||||||
|
Window *window = GetActiveWindow();
|
||||||
|
bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect);
|
||||||
|
if (mouse_in_document) {
|
||||||
|
View *view = GetView(window->active_view);
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
DocumentSelected = window;
|
||||||
|
|
||||||
|
Int p = ScreenSpaceToBufferPos(window, view, buffer, mouse);
|
||||||
|
Caret &caret = view->carets[0];
|
||||||
|
if (event.shift) {
|
||||||
|
if (p <= caret.range.min) {
|
||||||
|
caret.range.min = p;
|
||||||
|
caret.ifront = 0;
|
||||||
|
} else if (p >= caret.range.max) {
|
||||||
|
caret.range.max = p;
|
||||||
|
caret.ifront = 1;
|
||||||
|
}
|
||||||
|
} else if (event.mouse_double_click) {
|
||||||
|
view->carets.len = 1;
|
||||||
|
Range range = EncloseWord(buffer, p);
|
||||||
|
if (InBounds({caret.range.min - 1, caret.range.max + 1}, p)) {
|
||||||
|
caret = MakeCaret(range.max, range.min);
|
||||||
|
} else {
|
||||||
|
caret = MakeCaret(p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
view->carets.len = 1;
|
||||||
|
caret = MakeCaret(p);
|
||||||
|
}
|
||||||
|
DocumentRangeAnchor = caret.range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out scrollbar click
|
||||||
|
// @todo: probably need to refactor scrolling too :(
|
||||||
|
For(order) {
|
||||||
|
Window *window = &Windows[it];
|
||||||
|
if (!window->visible) continue;
|
||||||
|
bool mouse_in_scrollbar = CheckCollisionPointRec(mouse, window->scrollbar_rect);
|
||||||
|
if (mouse_in_scrollbar) {
|
||||||
|
ScrollbarSelected = window;
|
||||||
|
|
||||||
|
View *view = GetView(window->active_view);
|
||||||
|
Vec2 mouse_vec2 = MouseVec2();
|
||||||
|
Scroller s = ComputeScrollerRect(window);
|
||||||
|
double size_y = (double)GetSize(window->scrollbar_rect).y;
|
||||||
|
double p = mouse_vec2.y - window->scrollbar_rect.min.y;
|
||||||
|
if (mouse_vec2.y < s.rect.min.y || mouse_vec2.y > s.rect.max.y) {
|
||||||
|
view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)FontLineSpacing);
|
||||||
|
window->mouse_scroller_offset = -(double)GetSize(s.rect).y / 2.0 / size_y;
|
||||||
|
} else {
|
||||||
|
window->mouse_scroller_offset = (s.rect.min.y - p) / size_y;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle wheel scrolling
|
||||||
if (event.wheel.x || event.wheel.y) {
|
if (event.wheel.x || event.wheel.y) {
|
||||||
Scratch scratch;
|
|
||||||
Array<Int> order = GetWindowZOrder(scratch);
|
|
||||||
Vec2I mouse = MouseVec2I();
|
Vec2I mouse = MouseVec2I();
|
||||||
|
|
||||||
For(order) {
|
For(order) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = f
|
|||||||
|
|
||||||
Int pos = XYToPos(*buffer, xy);
|
Int pos = XYToPos(*buffer, xy);
|
||||||
if (shift) {
|
if (shift) {
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else {
|
} else {
|
||||||
it = MakeCaret(pos);
|
it = MakeCaret(pos);
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ void Command_MoveCursorsToSide(View *view, int direction, bool shift = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (shift) {
|
if (shift) {
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else {
|
} else {
|
||||||
it.range.max = it.range.min = pos;
|
it.range.max = it.range.min = pos;
|
||||||
}
|
}
|
||||||
@@ -60,13 +60,13 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
|
|||||||
case DIR_UP: {
|
case DIR_UP: {
|
||||||
if (ctrl && shift) {
|
if (ctrl && shift) {
|
||||||
Int pos = GetPrevEmptyLineStart(buffer, front);
|
Int pos = GetPrevEmptyLineStart(buffer, front);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else if (ctrl) {
|
} else if (ctrl) {
|
||||||
Int pos = GetPrevEmptyLineStart(buffer, it.range.min);
|
Int pos = GetPrevEmptyLineStart(buffer, it.range.min);
|
||||||
it = MakeCaret(pos);
|
it = MakeCaret(pos);
|
||||||
} else if (shift) {
|
} else if (shift) {
|
||||||
Int pos = OffsetByLine(buffer, front, -1);
|
Int pos = OffsetByLine(buffer, front, -1);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else {
|
} else {
|
||||||
if (range_size == 0) {
|
if (range_size == 0) {
|
||||||
Int pos = OffsetByLine(buffer, it.range.min, -1);
|
Int pos = OffsetByLine(buffer, it.range.min, -1);
|
||||||
@@ -79,13 +79,13 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
|
|||||||
case DIR_DOWN: {
|
case DIR_DOWN: {
|
||||||
if (ctrl && shift) {
|
if (ctrl && shift) {
|
||||||
Int pos = GetNextEmptyLineStart(buffer, front);
|
Int pos = GetNextEmptyLineStart(buffer, front);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else if (ctrl) {
|
} else if (ctrl) {
|
||||||
Int pos = GetNextEmptyLineStart(buffer, it.range.max);
|
Int pos = GetNextEmptyLineStart(buffer, it.range.max);
|
||||||
it = MakeCaret(pos);
|
it = MakeCaret(pos);
|
||||||
} else if (shift) {
|
} else if (shift) {
|
||||||
Int pos = OffsetByLine(buffer, front, 1);
|
Int pos = OffsetByLine(buffer, front, 1);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else {
|
} else {
|
||||||
if (range_size == 0) {
|
if (range_size == 0) {
|
||||||
Int pos = OffsetByLine(buffer, it.range.max, 1);
|
Int pos = OffsetByLine(buffer, it.range.max, 1);
|
||||||
@@ -98,7 +98,7 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
|
|||||||
case DIR_LEFT: {
|
case DIR_LEFT: {
|
||||||
if (ctrl && shift) {
|
if (ctrl && shift) {
|
||||||
Int pos = GetPrevWordStart(buffer, front);
|
Int pos = GetPrevWordStart(buffer, front);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else if (ctrl) {
|
} else if (ctrl) {
|
||||||
if (range_size != 0 && front != it.range.min) {
|
if (range_size != 0 && front != it.range.min) {
|
||||||
it = MakeCaret(it.range.min);
|
it = MakeCaret(it.range.min);
|
||||||
@@ -108,7 +108,7 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
|
|||||||
}
|
}
|
||||||
} else if (shift) {
|
} else if (shift) {
|
||||||
Int pos = GetPrevChar(buffer, front);
|
Int pos = GetPrevChar(buffer, front);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else {
|
} else {
|
||||||
if (range_size == 0) {
|
if (range_size == 0) {
|
||||||
Int pos = GetPrevChar(buffer, it.range.min);
|
Int pos = GetPrevChar(buffer, it.range.min);
|
||||||
@@ -121,7 +121,7 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
|
|||||||
case DIR_RIGHT: {
|
case DIR_RIGHT: {
|
||||||
if (ctrl && shift) {
|
if (ctrl && shift) {
|
||||||
Int pos = GetNextWordEnd(buffer, front);
|
Int pos = GetNextWordEnd(buffer, front);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else if (ctrl) {
|
} else if (ctrl) {
|
||||||
if (range_size != 0 && front != it.range.max) {
|
if (range_size != 0 && front != it.range.max) {
|
||||||
it = MakeCaret(it.range.max);
|
it = MakeCaret(it.range.max);
|
||||||
@@ -131,7 +131,7 @@ Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool
|
|||||||
}
|
}
|
||||||
} else if (shift) {
|
} else if (shift) {
|
||||||
Int pos = GetNextChar(buffer, front);
|
Int pos = GetNextChar(buffer, front);
|
||||||
it = ChangeFront(it, pos);
|
it = SetFront(it, pos);
|
||||||
} else {
|
} else {
|
||||||
if (range_size == 0) {
|
if (range_size == 0) {
|
||||||
Int pos = GetNextChar(buffer, it.range.max);
|
Int pos = GetNextChar(buffer, it.range.max);
|
||||||
@@ -521,29 +521,6 @@ Array<Range> FindAllInBuffer(Allocator allocator, Buffer *buffer, String16 needl
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GotoCrumb {
|
|
||||||
BufferID buffer_id;
|
|
||||||
Caret caret;
|
|
||||||
};
|
|
||||||
Array<GotoCrumb> GotoCrumbs;
|
|
||||||
|
|
||||||
void CheckpointBeforeGoto() {
|
|
||||||
Window *window = GetWindow(GetLastActiveWindow());
|
|
||||||
View *view = GetView(window->active_view);
|
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
|
||||||
Add(&GotoCrumbs, {buffer->id, view->carets[0]});
|
|
||||||
}
|
|
||||||
|
|
||||||
void GoBackToLastCrumb() {
|
|
||||||
Window *window = GetWindow(ActiveWindow);
|
|
||||||
if (GotoCrumbs.len <= 0) return;
|
|
||||||
GotoCrumb c = Pop(&GotoCrumbs);
|
|
||||||
Buffer *buffer = GetBuffer(c.buffer_id);
|
|
||||||
View *view = WindowOpenBufferView(window, buffer->name);
|
|
||||||
view->carets[0] = c.caret;
|
|
||||||
UpdateScroll(window, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Command_IdentedNewLine(View *view) {
|
void Command_IdentedNewLine(View *view) {
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
@@ -716,11 +693,7 @@ void WindowCommand(Event event, Window *window, View *view) {
|
|||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
String string = event.text;
|
String string = event.text;
|
||||||
String16 string16 = ToString16(scratch, string);
|
String16 string16 = ToString16(scratch, string);
|
||||||
|
|
||||||
Window *window = GetActiveWindow();
|
|
||||||
View *view = GetActiveView(window);
|
|
||||||
Command_Replace(view, string16);
|
Command_Replace(view, string16);
|
||||||
|
|
||||||
search = true;
|
search = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,145 +810,22 @@ void WindowCommand(Event event, Window *window, View *view) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Underline
|
|
||||||
if (event.ctrl) {
|
|
||||||
Caret caret = view->carets[0];
|
|
||||||
if (GetSize(caret.range) == 0) {
|
|
||||||
view->underline_pos[view->underline_count++] = caret.range.min;
|
|
||||||
Assert(view->underline_count <= 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Vec2I mouse = MouseVec2I();
|
|
||||||
Vec2I mworld = mouse - window->document_rect.min + view->scroll;
|
|
||||||
Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing};
|
|
||||||
XY xy = {(Int)(pos.x), (Int)(pos.y)};
|
|
||||||
Int p = XYToPosErrorOutOfBounds(*buffer, xy);
|
|
||||||
if (p != -1) {
|
|
||||||
view->underline_pos[view->underline_count++] = p;
|
|
||||||
Assert(view->underline_count <= 2);
|
|
||||||
|
|
||||||
if (Mouse(LEFT)) {
|
|
||||||
Range enclose = EncloseLoadWord(buffer, p);
|
|
||||||
String16 string = GetString(*buffer, enclose);
|
|
||||||
Open(string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.ctrl && Mouse(RIGHT)) {
|
|
||||||
GoBackToLastCrumb();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Ctrl(SDLK_Q)) {
|
if (Ctrl(SDLK_Q)) {
|
||||||
Int p = GetFront(view->carets[0]);
|
Int p = GetFront(view->carets[0]);
|
||||||
Range enclose = EncloseLoadWord(buffer, p);
|
Range enclose = EncloseLoadWord(buffer, p);
|
||||||
String16 string = GetString(*buffer, enclose);
|
String16 string = GetString(*buffer, enclose);
|
||||||
Open(string);
|
Open(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ctrl(SDLK_W)) {
|
if (Ctrl(SDLK_W)) {
|
||||||
GoBackToLastCrumb();
|
GoBackToLastCrumb();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (event.ctrl) {
|
||||||
|
Caret caret = view->carets[0];
|
||||||
Vec2I mouse = MouseVec2I();
|
if (GetSize(caret.range) == 0) {
|
||||||
|
view->underline_pos[view->underline_count++] = caret.range.min;
|
||||||
// Special case for full-screen where we can have document
|
Assert(view->underline_count <= 2);
|
||||||
// aligned with monitor screen in which case mouse cursor cannot
|
|
||||||
// be smaller then 0 which means we cannot scroll
|
|
||||||
if (mouse.y == 0 && window->document_rect.min.y == 0) {
|
|
||||||
float x, y;
|
|
||||||
SDL_GetGlobalMouseState(&x, &y);
|
|
||||||
if (y == 0) {
|
|
||||||
mouse.y = -10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect);
|
|
||||||
bool mouse_in_scrollbar = CheckCollisionPointRec(mouse, window->scrollbar_rect);
|
|
||||||
|
|
||||||
bool scrollbar_action = mouse_in_scrollbar || window->mouse_selecting_scrollbar;
|
|
||||||
bool document_action = false;
|
|
||||||
{
|
|
||||||
bool a = mouse_in_document && IsMouseEvent(event.kind);
|
|
||||||
bool b = window->mouse_selecting && !mouse_in_document;
|
|
||||||
document_action = a || b;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scrollbar_action && document_action) {
|
|
||||||
Vec2I mworld = mouse - window->document_rect.min + view->scroll;
|
|
||||||
Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing};
|
|
||||||
XY xy = {(Int)(pos.x), (Int)(pos.y)};
|
|
||||||
Int p = XYToPosWithoutNL(*buffer, xy);
|
|
||||||
|
|
||||||
if (mouse_in_document && Mouse(LEFT) && event.shift) {
|
|
||||||
Caret *c = &view->carets[0];
|
|
||||||
*c = ChangeFront(*c, p);
|
|
||||||
} else if (mouse_in_document && Mouse(LEFT) && event.mouse_double_click) {
|
|
||||||
Caret *c = &view->carets[0];
|
|
||||||
if (InBounds({c->range.min - 1, c->range.max + 1}, p)) {
|
|
||||||
c->range = EncloseWord(buffer, p);
|
|
||||||
view->selection_anchor = c->range;
|
|
||||||
} else {
|
|
||||||
view->selection_anchor = Rng(p);
|
|
||||||
}
|
|
||||||
} else if (mouse_in_document && Mouse(LEFT) && event.alt) {
|
|
||||||
Insert(&view->carets, MakeCaret(p, p), 0);
|
|
||||||
view->selection_anchor = view->carets[0].range;
|
|
||||||
} else if (mouse_in_document && Mouse(LEFT)) {
|
|
||||||
view->carets.len = 0;
|
|
||||||
Insert(&view->carets, MakeCaret(p, p), 0);
|
|
||||||
view->selection_anchor = view->carets[0].range;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mouse_in_document && Mouse(LEFT)) {
|
|
||||||
window->mouse_selecting = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window->mouse_selecting) {
|
|
||||||
if (Mouse(LEFT_UP)) {
|
|
||||||
window->mouse_selecting = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MergeCarets(view, &view->selection_anchor);
|
|
||||||
Caret &caret = view->carets[0];
|
|
||||||
if (view->selection_anchor.min > p) {
|
|
||||||
caret = MakeCaret(p, view->selection_anchor.max);
|
|
||||||
} else if (view->selection_anchor.max < p) {
|
|
||||||
caret = MakeCaret(p, view->selection_anchor.min);
|
|
||||||
} else {
|
|
||||||
caret = MakeCaret(view->selection_anchor.max, view->selection_anchor.min);
|
|
||||||
}
|
|
||||||
MergeCarets(view, &view->selection_anchor);
|
|
||||||
}
|
|
||||||
} else if (!(mouse_in_document || window->mouse_selecting) && mouse_in_scrollbar || window->mouse_selecting_scrollbar) {
|
|
||||||
Vec2 mouse_vec2 = MouseVec2();
|
|
||||||
Scroller s = ComputeScrollerRect(window);
|
|
||||||
double size_y = (double)GetSize(window->scrollbar_rect).y;
|
|
||||||
double p = mouse_vec2.y - window->scrollbar_rect.min.y;
|
|
||||||
|
|
||||||
if (Mouse(LEFT)) {
|
|
||||||
window->mouse_selecting_scrollbar = true;
|
|
||||||
} else if (Mouse(LEFT_UP)) {
|
|
||||||
window->mouse_selecting_scrollbar = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Mouse(LEFT)) {
|
|
||||||
if (mouse_vec2.y < s.rect.min.y || mouse_vec2.y > s.rect.max.y) {
|
|
||||||
view->scroll.y = (Int)(p / size_y * (double)s.line_count * (double)FontLineSpacing);
|
|
||||||
window->mouse_scroller_offset = -(double)GetSize(s.rect).y / 2.0 / size_y;
|
|
||||||
} else {
|
|
||||||
window->mouse_scroller_offset = (s.rect.min.y - p) / size_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window->mouse_selecting_scrollbar) {
|
|
||||||
double v = p / size_y;
|
|
||||||
v = v + (window->mouse_scroller_offset);
|
|
||||||
view->scroll.y = (Int)(v * (double)s.line_count * (double)FontLineSpacing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,18 @@ WindowID PopupWindowID;
|
|||||||
WindowID DebugWindowID;
|
WindowID DebugWindowID;
|
||||||
WindowID ConsoleWindowID;
|
WindowID ConsoleWindowID;
|
||||||
|
|
||||||
Array<WindowID> WindowSwitchHistory; // @todo: probably better as a circular buffer
|
// @note:
|
||||||
|
// Remember that WindowCommand works on window handed it down from HandleEvent
|
||||||
|
// just because we don't have NextActiveWindow doesn't mean that we work on new
|
||||||
|
// window all of a sudden in that function call!
|
||||||
WindowID ActiveWindow;
|
WindowID ActiveWindow;
|
||||||
WindowID NextActiveWindow;
|
Array<WindowID> WindowSwitchHistory; // @todo: probably better as a circular buffer
|
||||||
Int CaretChangeID;
|
Int CaretChangeID;
|
||||||
|
|
||||||
|
Window *ScrollbarSelected = NULL;
|
||||||
|
Window *DocumentSelected = NULL;
|
||||||
|
Range DocumentRangeAnchor;
|
||||||
|
|
||||||
inline ViewID AllocViewID() { return {ViewIDs.id++}; }
|
inline ViewID AllocViewID() { return {ViewIDs.id++}; }
|
||||||
inline WindowID AllocWindowID() { return {WindowIDs.id++}; }
|
inline WindowID AllocWindowID() { return {WindowIDs.id++}; }
|
||||||
inline BufferID AllocBufferID() { return {BufferIDs.id++}; }
|
inline BufferID AllocBufferID() { return {BufferIDs.id++}; }
|
||||||
@@ -102,7 +109,14 @@ WindowID GetLastActiveWindow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetActiveWindow(WindowID window) {
|
void SetActiveWindow(WindowID window) {
|
||||||
NextActiveWindow = window;
|
bool new_active_window = window.id != ActiveWindow.id;
|
||||||
|
if (new_active_window) {
|
||||||
|
ActiveWindow = window;
|
||||||
|
Window *w = GetWindow(window);
|
||||||
|
if (!w->dont_save_in_active_window_history) {
|
||||||
|
Add(&WindowSwitchHistory, window);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetActiveView(Window *window, ViewID view_id) {
|
void SetActiveView(Window *window, ViewID view_id) {
|
||||||
|
|||||||
@@ -155,39 +155,11 @@ void Update(Event event) {
|
|||||||
View *view = GetActiveView(window);
|
View *view = GetActiveView(window);
|
||||||
view->main_caret_on_begin_frame = view->carets[0];
|
view->main_caret_on_begin_frame = view->carets[0];
|
||||||
view->update_scroll = true;
|
view->update_scroll = true;
|
||||||
window->mouse_in_scrollbar = false;
|
|
||||||
view->underline_count = 0;
|
view->underline_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleEvent(event);
|
HandleEvent(event);
|
||||||
|
|
||||||
// Switch active window
|
|
||||||
{
|
|
||||||
bool active_window_changed = ActiveWindow.id != NextActiveWindow.id;
|
|
||||||
if (active_window_changed) {
|
|
||||||
Window *window = GetWindow(ActiveWindow);
|
|
||||||
window->mouse_selecting_scrollbar = false;
|
|
||||||
View *view = GetView(window->active_view);
|
|
||||||
view->underline_count = 0;
|
|
||||||
window->mouse_selecting = false;
|
|
||||||
ActiveWindow = NextActiveWindow;
|
|
||||||
{
|
|
||||||
Window *w = GetWindow(ActiveWindow);
|
|
||||||
if (!w->dont_save_in_active_window_history) {
|
|
||||||
Add(&WindowSwitchHistory, ActiveWindow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo: maybe move some of the mouse events to global comamnds?
|
|
||||||
// the problem here is that we don't want to click twice etc when
|
|
||||||
// window is inactive, we kind of also don't want to rerun events twice
|
|
||||||
// because it seems to be buggy and problematic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Mouse(LEFT_UP)) {
|
|
||||||
For(Windows) it.mouse_selecting = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReloadLuaConfig();
|
ReloadLuaConfig();
|
||||||
ReplaceDebugData();
|
ReplaceDebugData();
|
||||||
|
|
||||||
@@ -330,7 +302,7 @@ int main()
|
|||||||
WaitForEvents = true;
|
WaitForEvents = true;
|
||||||
Window *window = GetActiveWindow();
|
Window *window = GetActiveWindow();
|
||||||
View *view = GetView(window->active_view);
|
View *view = GetView(window->active_view);
|
||||||
if (window->mouse_selecting || window->mouse_selecting_scrollbar) {
|
if (DocumentSelected || ScrollbarSelected) {
|
||||||
WaitForEvents = false;
|
WaitForEvents = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ struct View {
|
|||||||
Array<Caret> carets;
|
Array<Caret> carets;
|
||||||
|
|
||||||
// window | view
|
// window | view
|
||||||
Range selection_anchor;
|
|
||||||
Caret main_caret_on_begin_frame;
|
Caret main_caret_on_begin_frame;
|
||||||
bool update_scroll;
|
bool update_scroll;
|
||||||
|
|
||||||
@@ -76,10 +75,6 @@ struct Window {
|
|||||||
int z;
|
int z;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool mouse_selecting_scrollbar : 1;
|
|
||||||
bool mouse_in_scrollbar : 1;
|
|
||||||
bool mouse_selecting : 1;
|
|
||||||
|
|
||||||
bool draw_scrollbar : 1;
|
bool draw_scrollbar : 1;
|
||||||
bool draw_line_numbers : 1;
|
bool draw_line_numbers : 1;
|
||||||
|
|
||||||
|
|||||||
@@ -3,17 +3,16 @@
|
|||||||
- I think the way sublime text and we display line highlights is confusing with multiple cursors (line highlight can be confused with selection)
|
- I think the way sublime text and we display line highlights is confusing with multiple cursors (line highlight can be confused with selection)
|
||||||
|
|
||||||
- mouse needs a rewrite
|
- mouse needs a rewrite
|
||||||
- you should be able to scroll another window without focusing it
|
|
||||||
- for now get rid of anchor maybe and do the - word select, line select
|
|
||||||
- make clicks global so that they work without needing another click to activate
|
|
||||||
- fix the bug where when we create a new view the anchor value on new view is compromised because and incongruent with position so we select from start of buffer
|
|
||||||
- hand cursor on hover over underlined word
|
- hand cursor on hover over underlined word
|
||||||
|
|
||||||
- maybe we don't need multiple cursors on mouse???
|
- maybe we don't need multiple cursors on mouse???
|
||||||
- ctrl + left mouse to load / ctrl + right mouse to go back
|
- ctrl + left mouse to load / ctrl + right mouse to go back
|
||||||
- alt + left to exec / alt + right to toggle console or something related
|
- alt + left to exec / alt + right to toggle console or something related
|
||||||
- similar mirroring on keyboard with W/Q Ctrl/Alt
|
- similar mirroring on keyboard with W/Q Ctrl/Alt
|
||||||
- mid click to create new cursor?
|
- mid click to create new cursor?
|
||||||
|
|
||||||
|
- mid click - create new cursor
|
||||||
|
- mid click hold - create a rectangle selection with multiple cursors on each line
|
||||||
|
|
||||||
- delete multiple spaces (based on indent size) on delete instead one by one. It should only work at beginning of line, in indent area
|
- delete multiple spaces (based on indent size) on delete instead one by one. It should only work at beginning of line, in indent area
|
||||||
- switch to previous view (ctrl + tab)
|
- switch to previous view (ctrl + tab)
|
||||||
- we could rewrite kill lines with simpler commands - extend selection to encompass lines->replace
|
- we could rewrite kill lines with simpler commands - extend selection to encompass lines->replace
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ void DrawWindow(Window *window) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; is_active && i < view->underline_count; i += 1) {
|
for (int i = 0; i < view->underline_count; i += 1) {
|
||||||
Range range = EncloseLoadWord(buffer, view->underline_pos[i]);
|
Range range = EncloseLoadWord(buffer, view->underline_pos[i]);
|
||||||
|
|
||||||
XY xy_min = PosToXY(*buffer, range.min);
|
XY xy_min = PosToXY(*buffer, range.min);
|
||||||
@@ -240,9 +240,7 @@ void DrawWindow(Window *window) {
|
|||||||
Scroller scroller = ComputeScrollerRect(window);
|
Scroller scroller = ComputeScrollerRect(window);
|
||||||
Rect2 rect = Shrink(scroller.rect, 2);
|
Rect2 rect = Shrink(scroller.rect, 2);
|
||||||
Color color = ColorScrollbarScroller;
|
Color color = ColorScrollbarScroller;
|
||||||
if (!window->mouse_selecting && (window->mouse_selecting_scrollbar || window->mouse_in_scrollbar)) {
|
if (ScrollbarSelected == window) color = ColorScrollbarScrollerSelected;
|
||||||
if (is_active) color = ColorScrollbarScrollerSelected;
|
|
||||||
}
|
|
||||||
DrawRect(rect, color);
|
DrawRect(rect, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user