Mouse rewrite
This commit is contained in:
@@ -85,18 +85,29 @@ Caret MakeCaret(Int front, Int back) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Caret ChangeBack(Caret caret, Int back) {
|
||||
Caret SetBack(Caret caret, Int back) {
|
||||
Int front = GetFront(caret);
|
||||
Caret result = MakeCaret(front, back);
|
||||
return result;
|
||||
}
|
||||
|
||||
Caret ChangeFront(Caret caret, Int front) {
|
||||
Caret SetFront(Caret caret, Int front) {
|
||||
Int back = GetBack(caret);
|
||||
Caret result = MakeCaret(front, back);
|
||||
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 result = pos >= 0 && pos < buffer.len;
|
||||
return result;
|
||||
|
||||
@@ -60,6 +60,7 @@ bool SHIFT_PRESSED = true;
|
||||
Vec2I { (Int) event.xmouse, (Int)event.ymouse }
|
||||
#define Mouse(x) (event.kind == EVENT_MOUSE_##x)
|
||||
#define MousePress() (Mouse(LEFT) || Mouse(RIGHT) || Mouse(MIDDLE))
|
||||
#define MouseUp() (Mouse(LEFT_UP) || Mouse(RIGHT_UP) || Mouse(MIDDLE_UP))
|
||||
|
||||
void ToggleFullscreen() {
|
||||
if (IsInFullscreen) {
|
||||
@@ -78,54 +79,241 @@ void ToggleFullscreen() {
|
||||
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) {
|
||||
ProfileFunction();
|
||||
bool run_window_command = true;
|
||||
|
||||
//
|
||||
// Window cursor setting
|
||||
//
|
||||
Scratch scratch;
|
||||
Array<Int> order = GetWindowZOrder(scratch);
|
||||
{
|
||||
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);
|
||||
if (SDL_MouseCursor) {
|
||||
SDL_DestroyCursor(SDL_MouseCursor);
|
||||
SDL_MouseCursor = NULL;
|
||||
}
|
||||
|
||||
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) {
|
||||
Vec2I mouse = MouseVec2I();
|
||||
For(order) {
|
||||
Window *window = &Windows[it];
|
||||
if (!window->visible) continue;
|
||||
bool mouse_in_total = CheckCollisionPointRec(mouse, window->total_rect);
|
||||
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);
|
||||
} else {
|
||||
SDL_MouseCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER);
|
||||
SDL_SetCursor(SDL_MouseCursor);
|
||||
}
|
||||
}
|
||||
|
||||
if (MousePress()) {
|
||||
Scratch scratch;
|
||||
Array<Int> order = GetWindowZOrder(scratch);
|
||||
Vec2I mouse = MouseVec2I();
|
||||
// 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_window = CheckCollisionPointRec(mouse, window->total_rect);
|
||||
if (mouse_in_window) {
|
||||
bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect);
|
||||
if (mouse_in_document) {
|
||||
SetActiveWindow(window->id);
|
||||
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) {
|
||||
Scratch scratch;
|
||||
Array<Int> order = GetWindowZOrder(scratch);
|
||||
Vec2I mouse = MouseVec2I();
|
||||
Vec2I mouse = MouseVec2I();
|
||||
|
||||
For(order) {
|
||||
Window *window = &Windows[it];
|
||||
|
||||
@@ -20,7 +20,7 @@ void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = f
|
||||
|
||||
Int pos = XYToPos(*buffer, xy);
|
||||
if (shift) {
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
it = MakeCaret(pos);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ void Command_MoveCursorsToSide(View *view, int direction, bool shift = false) {
|
||||
}
|
||||
|
||||
if (shift) {
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
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: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetPrevEmptyLineStart(buffer, front);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
Int pos = GetPrevEmptyLineStart(buffer, it.range.min);
|
||||
it = MakeCaret(pos);
|
||||
} else if (shift) {
|
||||
Int pos = OffsetByLine(buffer, front, -1);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
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: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetNextEmptyLineStart(buffer, front);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
Int pos = GetNextEmptyLineStart(buffer, it.range.max);
|
||||
it = MakeCaret(pos);
|
||||
} else if (shift) {
|
||||
Int pos = OffsetByLine(buffer, front, 1);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
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: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetPrevWordStart(buffer, front);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
if (range_size != 0 && front != 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) {
|
||||
Int pos = GetPrevChar(buffer, front);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
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: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetNextWordEnd(buffer, front);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
if (range_size != 0 && front != 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) {
|
||||
Int pos = GetNextChar(buffer, front);
|
||||
it = ChangeFront(it, pos);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = GetNextChar(buffer, it.range.max);
|
||||
@@ -521,29 +521,6 @@ Array<Range> FindAllInBuffer(Allocator allocator, Buffer *buffer, String16 needl
|
||||
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) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Scratch scratch;
|
||||
@@ -716,11 +693,7 @@ void WindowCommand(Event event, Window *window, View *view) {
|
||||
Scratch scratch;
|
||||
String string = event.text;
|
||||
String16 string16 = ToString16(scratch, string);
|
||||
|
||||
Window *window = GetActiveWindow();
|
||||
View *view = GetActiveView(window);
|
||||
Command_Replace(view, string16);
|
||||
|
||||
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)) {
|
||||
Int p = GetFront(view->carets[0]);
|
||||
Range enclose = EncloseLoadWord(buffer, p);
|
||||
String16 string = GetString(*buffer, enclose);
|
||||
Open(string);
|
||||
}
|
||||
|
||||
if (Ctrl(SDLK_W)) {
|
||||
GoBackToLastCrumb();
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
Vec2I mouse = MouseVec2I();
|
||||
|
||||
// Special case for full-screen where we can have document
|
||||
// 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,18 @@ WindowID PopupWindowID;
|
||||
WindowID DebugWindowID;
|
||||
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 NextActiveWindow;
|
||||
Array<WindowID> WindowSwitchHistory; // @todo: probably better as a circular buffer
|
||||
Int CaretChangeID;
|
||||
|
||||
Window *ScrollbarSelected = NULL;
|
||||
Window *DocumentSelected = NULL;
|
||||
Range DocumentRangeAnchor;
|
||||
|
||||
inline ViewID AllocViewID() { return {ViewIDs.id++}; }
|
||||
inline WindowID AllocWindowID() { return {WindowIDs.id++}; }
|
||||
inline BufferID AllocBufferID() { return {BufferIDs.id++}; }
|
||||
@@ -102,7 +109,14 @@ WindowID GetLastActiveWindow() {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -155,39 +155,11 @@ void Update(Event event) {
|
||||
View *view = GetActiveView(window);
|
||||
view->main_caret_on_begin_frame = view->carets[0];
|
||||
view->update_scroll = true;
|
||||
window->mouse_in_scrollbar = false;
|
||||
view->underline_count = 0;
|
||||
}
|
||||
|
||||
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();
|
||||
ReplaceDebugData();
|
||||
|
||||
@@ -330,7 +302,7 @@ int main()
|
||||
WaitForEvents = true;
|
||||
Window *window = GetActiveWindow();
|
||||
View *view = GetView(window->active_view);
|
||||
if (window->mouse_selecting || window->mouse_selecting_scrollbar) {
|
||||
if (DocumentSelected || ScrollbarSelected) {
|
||||
WaitForEvents = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ struct View {
|
||||
Array<Caret> carets;
|
||||
|
||||
// window | view
|
||||
Range selection_anchor;
|
||||
Caret main_caret_on_begin_frame;
|
||||
bool update_scroll;
|
||||
|
||||
@@ -76,10 +75,6 @@ struct Window {
|
||||
int z;
|
||||
|
||||
struct {
|
||||
bool mouse_selecting_scrollbar : 1;
|
||||
bool mouse_in_scrollbar : 1;
|
||||
bool mouse_selecting : 1;
|
||||
|
||||
bool draw_scrollbar : 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)
|
||||
|
||||
- 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
|
||||
- maybe we don't need multiple cursors on mouse???
|
||||
- ctrl + left mouse to load / ctrl + right mouse to go back
|
||||
- alt + left to exec / alt + right to toggle console or something related
|
||||
- similar mirroring on keyboard with W/Q Ctrl/Alt
|
||||
- mid click to create new cursor?
|
||||
|
||||
- mid click - create new cursor
|
||||
- mid click hold - create a rectangle selection with multiple cursors on each line
|
||||
|
||||
- maybe we don't need multiple cursors on mouse???
|
||||
- ctrl + left mouse to load / ctrl + right mouse to go back
|
||||
- alt + left to exec / alt + right to toggle console or something related
|
||||
- similar mirroring on keyboard with W/Q Ctrl/Alt
|
||||
- mid click to create new cursor?
|
||||
- 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)
|
||||
- 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]);
|
||||
|
||||
XY xy_min = PosToXY(*buffer, range.min);
|
||||
@@ -240,9 +240,7 @@ void DrawWindow(Window *window) {
|
||||
Scroller scroller = ComputeScrollerRect(window);
|
||||
Rect2 rect = Shrink(scroller.rect, 2);
|
||||
Color color = ColorScrollbarScroller;
|
||||
if (!window->mouse_selecting && (window->mouse_selecting_scrollbar || window->mouse_in_scrollbar)) {
|
||||
if (is_active) color = ColorScrollbarScrollerSelected;
|
||||
}
|
||||
if (ScrollbarSelected == window) color = ColorScrollbarScrollerSelected;
|
||||
DrawRect(rect, color);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user