Răsfoiți Sursa

fix(gtk): Correct visual cursor misplacement and improve font metrics. This commit addresses the issue where the visual cursor would not redraw in the correct position despite logical cursor updates. The Pango::Layout is now always updated with the current line's text before cursor position calculations, resolving misplacement. Character width calculation is also refined.

Bernardo Magri 1 lună în urmă
părinte
comite
30d115bb9e
1 a modificat fișierele cu 26 adăugiri și 7 ștergeri
  1. 26 7
      src/gtk_renderer.cpp

+ 26 - 7
src/gtk_renderer.cpp

@@ -2,6 +2,7 @@
 #include "lumacs/editor_core.hpp"
 #include "lumacs/minibuffer_manager.hpp" // For MinibufferManager and MinibufferMode
 #include <algorithm> // For std::max, std::min
+#include <spdlog/spdlog.h> // Added for debug logging
 
 namespace lumacs {
 
@@ -13,8 +14,8 @@ GtkRenderer::GtkRenderer(EditorCore& core, Gtk::DrawingArea& main_drawing_area)
 void GtkRenderer::initialize_font_metrics() {
     if (font_initialized_) return;
 
-    // Use the main_drawing_area_ to create a Pango layout for font metrics
-    auto layout = main_drawing_area_.create_pango_layout("m");
+    // Use a minimal string for layout creation
+    auto layout = main_drawing_area_.create_pango_layout(" ");
     font_desc_ = Pango::FontDescription("Monospace 12");
     layout->set_font_description(font_desc_);
     
@@ -22,9 +23,13 @@ void GtkRenderer::initialize_font_metrics() {
     line_height_ = (double)metrics.get_height() / PANGO_SCALE;
     ascent_ = (double)metrics.get_ascent() / PANGO_SCALE;
     
-    Pango::Rectangle ink_rect, logical_rect;
-    layout->get_pixel_extents(ink_rect, logical_rect);
-    char_width_ = (double)logical_rect.get_width();
+    // Get character width more precisely using index_to_pos for a known monospace char
+    layout->set_text("M"); // Use a single, representative character
+    Pango::Rectangle pos0 = layout->index_to_pos(0); // Position at index 0 (before 'M')
+    Pango::Rectangle pos1 = layout->index_to_pos(1); // Position at index 1 (after 'M')
+    char_width_ = (double)(pos1.get_x() - pos0.get_x()) / PANGO_SCALE;
+
+    spdlog::debug("GtkRenderer font metrics: line_height={}, char_width={}", line_height_, char_width_);
     
     font_initialized_ = true;
 }
@@ -195,6 +200,9 @@ void GtkRenderer::draw_window(const Cairo::RefPtr<Cairo::Context>& cr, int width
                 visible_text = line_text.substr(horizontal_offset);
             }
             
+            // Always set text for the layout before any further operations, especially cursor positioning
+            layout->set_text(visible_text);
+            
             double text_x = PADDING_LEFT;
             double text_y = PADDING_TOP + screen_y * line_height_;
     
@@ -230,7 +238,7 @@ void GtkRenderer::draw_window(const Cairo::RefPtr<Cairo::Context>& cr, int width
     
             if (!use_cache) {
                 // Draw fresh
-                layout->set_text(visible_text);
+                // layout->set_text(visible_text); // Moved this line outside the if block
                 Pango::AttrList attr_list;
     
                 // 1. Apply Syntax Highlighting
@@ -302,22 +310,33 @@ void GtkRenderer::draw_window(const Cairo::RefPtr<Cairo::Context>& cr, int width
             if (is_active_window && cursor_visible_ && buffer_line_idx == cursor.line) {
                  int cursor_idx = static_cast<int>(cursor.column) - horizontal_offset;
                  
+                 spdlog::debug("Cursor debug: Logical Curs ({},{}) | H-Offset {} | VisTextLen {} | CursorIdx {}",
+                               cursor.line, cursor.column, horizontal_offset, visible_text.length(), cursor_idx);
+
                  Pango::Rectangle pos;
                  if (cursor_idx < 0) {
                      // Out of view
+                     spdlog::debug("Cursor debug: Cursor out of view (left)");
+                     continue; // Don't draw if out of view
                  } else if (cursor_idx > static_cast<int>(visible_text.length())) {
-                      // Past end of line
+                      // Past end of line (after last character)
                       pos = layout->index_to_pos(visible_text.length()); 
                       int diff = cursor_idx - static_cast<int>(visible_text.length());
                       if (diff > 0) {
                            pos.set_x(pos.get_x() + diff * char_width_ * PANGO_SCALE);
                       }
+                      spdlog::debug("Cursor debug: Past end of line. PangoX={}, FinalPangoX={}", layout->index_to_pos(visible_text.length()).get_x(), pos.get_x());
+
                  } else {
                      pos = layout->index_to_pos(cursor_idx);
+                     spdlog::debug("Cursor debug: Within line. PangoX={}", pos.get_x());
                  }
     
                  double cursor_screen_x = PADDING_LEFT + (pos.get_x() / (double)PANGO_SCALE);
                  
+                 spdlog::debug("Cursor debug: ScreenX={}, ScreenY={} | CharWidth={}, LineHeight={}",
+                               cursor_screen_x, text_y, char_width_, line_height_);
+
                  if (cursor_screen_x >= PADDING_LEFT && cursor_screen_x < (width - PADDING_RIGHT)) {
                      // Determine cursor width
                      double cur_width = char_width_;