Add 'CenterOnCursor' command and improve cursor scrolling logic
- Introduced `CommandId::CenterOnCursor` to center viewport on the cursor line. - Improved scrolling behavior in `ImGuiRenderer` to avoid aggressive centering and keep visible lines stable. - Updated `make-app-release` to rename the output app to `kge-qt.app`. - Adjusted padding in `ImGuiFrontend` to align with `ImGuiRenderer` settings for consistent scrolling. - Bumped version to 1.4.1.
This commit is contained in:
@@ -4,7 +4,7 @@ project(kte)
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(KTE_VERSION "1.4.0")
|
set(KTE_VERSION "1.4.1")
|
||||||
|
|
||||||
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
||||||
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
||||||
|
|||||||
32
Command.cc
32
Command.cc
@@ -109,6 +109,33 @@ ensure_cursor_visible(const Editor &ed, Buffer &buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cmd_center_on_cursor(CommandContext &ctx)
|
||||||
|
{
|
||||||
|
Buffer *buf = ctx.editor.CurrentBuffer();
|
||||||
|
if (!buf)
|
||||||
|
return false;
|
||||||
|
const auto &rows = buf->Rows();
|
||||||
|
std::size_t total = rows.size();
|
||||||
|
std::size_t content = ctx.editor.ContentRows();
|
||||||
|
if (content == 0)
|
||||||
|
content = 1;
|
||||||
|
std::size_t cy = buf->Cury();
|
||||||
|
std::size_t half = content / 2;
|
||||||
|
std::size_t new_rowoffs = (cy > half) ? (cy - half) : 0;
|
||||||
|
// Clamp to valid range
|
||||||
|
if (total > content) {
|
||||||
|
std::size_t max_rowoffs = total - content;
|
||||||
|
if (new_rowoffs > max_rowoffs)
|
||||||
|
new_rowoffs = max_rowoffs;
|
||||||
|
} else {
|
||||||
|
new_rowoffs = 0;
|
||||||
|
}
|
||||||
|
buf->SetOffsets(new_rowoffs, buf->Coloffs());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ensure_at_least_one_line(Buffer &buf)
|
ensure_at_least_one_line(Buffer &buf)
|
||||||
{
|
{
|
||||||
@@ -4445,6 +4472,11 @@ InstallDefaultCommands()
|
|||||||
// Syntax highlighting (public commands)
|
// Syntax highlighting (public commands)
|
||||||
CommandRegistry::Register({CommandId::Syntax, "syntax", "Syntax: on|off|reload", cmd_syntax, true});
|
CommandRegistry::Register({CommandId::Syntax, "syntax", "Syntax: on|off|reload", cmd_syntax, true});
|
||||||
CommandRegistry::Register({CommandId::SetOption, "set", "Set option: key=value", cmd_set_option, true});
|
CommandRegistry::Register({CommandId::SetOption, "set", "Set option: key=value", cmd_set_option, true});
|
||||||
|
// Viewport control
|
||||||
|
CommandRegistry::Register({
|
||||||
|
CommandId::CenterOnCursor, "center-on-cursor", "Center viewport on current line", cmd_center_on_cursor,
|
||||||
|
false, false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ enum class CommandId {
|
|||||||
// Syntax highlighting
|
// Syntax highlighting
|
||||||
Syntax, // ":syntax on|off|reload"
|
Syntax, // ":syntax on|off|reload"
|
||||||
SetOption, // generic ":set key=value" (v1: filetype=<lang>)
|
SetOption, // generic ":set key=value" (v1: filetype=<lang>)
|
||||||
|
// Viewport control
|
||||||
|
CenterOnCursor, // center the viewport on the current cursor line (C-k k)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -272,10 +272,11 @@ GUIFrontend::Step(Editor &ed, bool &running)
|
|||||||
float disp_w = io.DisplaySize.x > 0 ? io.DisplaySize.x : static_cast<float>(width_);
|
float disp_w = io.DisplaySize.x > 0 ? io.DisplaySize.x : static_cast<float>(width_);
|
||||||
float disp_h = io.DisplaySize.y > 0 ? io.DisplaySize.y : static_cast<float>(height_);
|
float disp_h = io.DisplaySize.y > 0 ? io.DisplaySize.y : static_cast<float>(height_);
|
||||||
|
|
||||||
// Account for the GUI window padding and the status bar height used in GUIRenderer
|
// Account for the GUI window padding and the status bar height used in ImGuiRenderer.
|
||||||
const ImGuiStyle &style = ImGui::GetStyle();
|
// ImGuiRenderer pushes WindowPadding = (6,6) every frame, so use the same constants here
|
||||||
float pad_x = style.WindowPadding.x;
|
// to avoid mismatches that would cause premature scrolling.
|
||||||
float pad_y = style.WindowPadding.y;
|
const float pad_x = 6.0f;
|
||||||
|
const float pad_y = 6.0f;
|
||||||
// Status bar reserves one frame height (with spacing) inside the window
|
// Status bar reserves one frame height (with spacing) inside the window
|
||||||
float status_h = ImGui::GetFrameHeightWithSpacing();
|
float status_h = ImGui::GetFrameHeightWithSpacing();
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,8 @@ ImGuiRenderer::Draw(Editor &ed)
|
|||||||
prev_buf_coloffs = buf_coloffs;
|
prev_buf_coloffs = buf_coloffs;
|
||||||
|
|
||||||
// Synchronize cursor and scrolling.
|
// Synchronize cursor and scrolling.
|
||||||
// Ensure the cursor is visible even on the first frame or when it didn't move.
|
// Ensure the cursor is visible, but avoid aggressive centering so that
|
||||||
|
// the same lines remain visible until the cursor actually goes off-screen.
|
||||||
{
|
{
|
||||||
// Compute visible row range using the child window height
|
// Compute visible row range using the child window height
|
||||||
float child_h = ImGui::GetWindowHeight();
|
float child_h = ImGui::GetWindowHeight();
|
||||||
@@ -151,15 +152,30 @@ ImGuiRenderer::Draw(Editor &ed)
|
|||||||
long last_row = first_row + vis_rows - 1;
|
long last_row = first_row + vis_rows - 1;
|
||||||
|
|
||||||
long cyr = static_cast<long>(cy);
|
long cyr = static_cast<long>(cy);
|
||||||
if (cyr < first_row || cyr > last_row) {
|
if (cyr < first_row) {
|
||||||
float target = (static_cast<float>(cyr) - std::max(0L, vis_rows / 2)) * row_h;
|
// Scroll just enough to bring the cursor line to the top
|
||||||
|
float target = static_cast<float>(cyr) * row_h;
|
||||||
|
if (target < 0.f)
|
||||||
|
target = 0.f;
|
||||||
|
float max_y = ImGui::GetScrollMaxY();
|
||||||
|
if (max_y >= 0.f && target > max_y)
|
||||||
|
target = max_y;
|
||||||
|
ImGui::SetScrollY(target);
|
||||||
|
scroll_y = ImGui::GetScrollY();
|
||||||
|
first_row = static_cast<long>(scroll_y / row_h);
|
||||||
|
last_row = first_row + vis_rows - 1;
|
||||||
|
} else if (cyr > last_row) {
|
||||||
|
// Scroll just enough to bring the cursor line to the bottom
|
||||||
|
long new_first = cyr - vis_rows + 1;
|
||||||
|
if (new_first < 0)
|
||||||
|
new_first = 0;
|
||||||
|
float target = static_cast<float>(new_first) * row_h;
|
||||||
float max_y = ImGui::GetScrollMaxY();
|
float max_y = ImGui::GetScrollMaxY();
|
||||||
if (target < 0.f)
|
if (target < 0.f)
|
||||||
target = 0.f;
|
target = 0.f;
|
||||||
if (max_y >= 0.f && target > max_y)
|
if (max_y >= 0.f && target > max_y)
|
||||||
target = max_y;
|
target = max_y;
|
||||||
ImGui::SetScrollY(target);
|
ImGui::SetScrollY(target);
|
||||||
// refresh local variables
|
|
||||||
scroll_y = ImGui::GetScrollY();
|
scroll_y = ImGui::GetScrollY();
|
||||||
first_row = static_cast<long>(scroll_y / row_h);
|
first_row = static_cast<long>(scroll_y / row_h);
|
||||||
last_row = first_row + vis_rows - 1;
|
last_row = first_row + vis_rows - 1;
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ KLookupKCommand(const int ascii_key, const bool ctrl, CommandId &out) -> bool
|
|||||||
case 'a':
|
case 'a':
|
||||||
out = CommandId::MarkAllAndJumpEnd;
|
out = CommandId::MarkAllAndJumpEnd;
|
||||||
return true;
|
return true;
|
||||||
|
case 'k':
|
||||||
|
out = CommandId::CenterOnCursor; // C-k k center current line
|
||||||
|
return true;
|
||||||
case 'b':
|
case 'b':
|
||||||
out = CommandId::BufferSwitchStart;
|
out = CommandId::BufferSwitchStart;
|
||||||
return true;
|
return true;
|
||||||
@@ -215,4 +218,4 @@ KLookupEscCommand(const int ascii_key, CommandId &out) -> bool
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -20,9 +20,10 @@ cmake -S . -B cmake-build-release -DBUILD_GUI=ON -DCMAKE_BUILD_TYPE=Release -DEN
|
|||||||
|
|
||||||
cd cmake-build-release-qt
|
cd cmake-build-release-qt
|
||||||
make clean
|
make clean
|
||||||
rm -fr kge.app*
|
rm -fr kge.app* kge-qt.app*
|
||||||
make
|
make
|
||||||
zip -r kge.app.zip kge.app
|
mv kge.app kge-qt.app
|
||||||
sha256sum kge.app.zip
|
zip -r kge-qt.app.zip kge-qt.app
|
||||||
|
sha256sum kge-qt.app.zip
|
||||||
open .
|
open .
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
Reference in New Issue
Block a user