|
|
@@ -54,7 +54,21 @@ public:
|
|
|
private:
|
|
|
EditorCore* core_;
|
|
|
Glib::RefPtr<Gtk::Application> app_;
|
|
|
- // Window is managed by Gtk::Application
|
|
|
+ // Input Mode State
|
|
|
+ enum class Mode {
|
|
|
+ Normal,
|
|
|
+ Command,
|
|
|
+ FindFile,
|
|
|
+ BufferSwitch,
|
|
|
+ KillBuffer,
|
|
|
+ ConfirmKill,
|
|
|
+ ISearch
|
|
|
+ };
|
|
|
+ Mode mode_ = Mode::Normal;
|
|
|
+ std::string command_buffer_;
|
|
|
+ std::string message_line_;
|
|
|
+
|
|
|
+ // Member variables
|
|
|
Gtk::DrawingArea* drawing_area_ = nullptr;
|
|
|
double char_width_ = 0;
|
|
|
double line_height_ = 0;
|
|
|
@@ -63,7 +77,8 @@ private:
|
|
|
protected:
|
|
|
void on_activate() {
|
|
|
// Create main window and associate with the application
|
|
|
- auto window = Glib::RefPtr<LumacsWindow>(new LumacsWindow(app_));
|
|
|
+ // Gtk::ApplicationWindow constructor adds it to the application, which manages lifetime.
|
|
|
+ auto* window = new LumacsWindow(app_);
|
|
|
|
|
|
// Create drawing area for text rendering
|
|
|
drawing_area_ = Gtk::make_managed<Gtk::DrawingArea>();
|
|
|
@@ -158,20 +173,13 @@ protected:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Input
|
|
|
- bool on_key_pressed(guint keyval, guint /*keycode*/, Gdk::ModifierType state) {
|
|
|
- std::string key_name;
|
|
|
-
|
|
|
+ std::string resolve_key(guint keyval, Gdk::ModifierType state) {
|
|
|
// Handle modifier keys
|
|
|
unsigned int state_uint = static_cast<unsigned int>(state);
|
|
|
bool is_control = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::CONTROL_MASK)) != 0;
|
|
|
- bool is_alt = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::ALT_MASK)) != 0;
|
|
|
- bool is_meta = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::META_MASK)) != 0;
|
|
|
|
|
|
- // Combine Alt and Meta logic for Lumacs "M-"
|
|
|
- bool is_lumacs_meta = is_alt || is_meta;
|
|
|
-
|
|
|
// Convert keyval to string
|
|
|
+ std::string key_name;
|
|
|
switch (keyval) {
|
|
|
case GDK_KEY_Return: key_name = "Return"; break;
|
|
|
case GDK_KEY_Tab: key_name = "Tab"; break;
|
|
|
@@ -190,36 +198,95 @@ protected:
|
|
|
// Handle printable characters
|
|
|
if (keyval >= GDK_KEY_a && keyval <= GDK_KEY_z) {
|
|
|
key_name = std::string(1, static_cast<char>(keyval));
|
|
|
- if (is_control) { // Special handling for C-a to C-z
|
|
|
- // GDK sends keyval for 'a' to 'z' even with Control.
|
|
|
- // Lumacs expects 'C-a' not 'C-S-a' if Shift is also pressed.
|
|
|
- // So we only take the base character and then apply C- modifier.
|
|
|
- } else if ((static_cast<unsigned int>(state) & static_cast<unsigned int>(Gdk::ModifierType::SHIFT_MASK)) != 0) { // Shift-a is 'A' etc.
|
|
|
+ if (is_control) {
|
|
|
+ // Logic for Control keys if needed
|
|
|
+ } else if ((state_uint & static_cast<unsigned int>(Gdk::ModifierType::SHIFT_MASK)) != 0) {
|
|
|
key_name = std::string(1, static_cast<char>(keyval - (GDK_KEY_a - GDK_KEY_A)));
|
|
|
}
|
|
|
} else if (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) {
|
|
|
key_name = std::string(1, static_cast<char>(keyval));
|
|
|
- } else if (keyval >= 32 && keyval <= 126) { // Other printable ASCII
|
|
|
+ } else if (keyval >= 32 && keyval <= 126) {
|
|
|
key_name = std::string(1, static_cast<char>(keyval));
|
|
|
- } else {
|
|
|
- return false; // Unhandled key
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
+ return key_name;
|
|
|
+ }
|
|
|
|
|
|
- if (key_name.empty()) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ // Input
|
|
|
+ bool on_key_pressed(guint keyval, guint /*keycode*/, Gdk::ModifierType state) {
|
|
|
+ // 1. Resolve the base key name
|
|
|
+ std::string key_name = resolve_key(keyval, state);
|
|
|
+ if (key_name.empty()) return false;
|
|
|
|
|
|
- // Apply modifiers
|
|
|
- if (is_control && key_name.length() == 1) { // Only apply C- to single chars, not special keys
|
|
|
- key_name = "C-" + key_name;
|
|
|
- }
|
|
|
- if (is_lumacs_meta) {
|
|
|
- key_name = "M-" + key_name;
|
|
|
+ // 2. Handle Modifiers
|
|
|
+ unsigned int state_uint = static_cast<unsigned int>(state);
|
|
|
+ bool is_control = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::CONTROL_MASK)) != 0;
|
|
|
+ bool is_alt = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::ALT_MASK)) != 0;
|
|
|
+ bool is_meta = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::META_MASK)) != 0;
|
|
|
+ bool is_lumacs_meta = is_alt || is_meta;
|
|
|
+
|
|
|
+ // 3. Handle Minibuffer Input Logic (Command/Buffer/File modes)
|
|
|
+ // If in a special mode, we might consume the key directly instead of passing to Lua bindings,
|
|
|
+ // UNLESS it's a control sequence like C-g or Return.
|
|
|
+ if (mode_ != Mode::Normal && mode_ != Mode::ISearch) {
|
|
|
+ if (key_name == "Escape" || (is_control && key_name == "g")) { // C-g
|
|
|
+ mode_ = Mode::Normal;
|
|
|
+ command_buffer_.clear();
|
|
|
+ message_line_ = "Cancelled";
|
|
|
+ if (drawing_area_) drawing_area_->queue_draw();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (key_name == "Return") {
|
|
|
+ // Execute command logic
|
|
|
+ if (mode_ == Mode::Command) {
|
|
|
+ if (command_buffer_ == "quit" || command_buffer_ == "q") {
|
|
|
+ app_->quit();
|
|
|
+ } else {
|
|
|
+ core_->lua_api()->execute(command_buffer_);
|
|
|
+ message_line_ = "Executed: " + command_buffer_;
|
|
|
+ }
|
|
|
+ } else if (mode_ == Mode::FindFile) {
|
|
|
+ if (core_->load_file(command_buffer_)) message_line_ = "Loaded";
|
|
|
+ else message_line_ = "Failed to load";
|
|
|
+ } else if (mode_ == Mode::BufferSwitch) {
|
|
|
+ if (core_->switch_buffer_in_window(command_buffer_)) message_line_ = "Switched";
|
|
|
+ else message_line_ = "Buffer not found";
|
|
|
+ }
|
|
|
+
|
|
|
+ mode_ = Mode::Normal;
|
|
|
+ command_buffer_.clear();
|
|
|
+ if (drawing_area_) drawing_area_->queue_draw();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (key_name == "Backspace") {
|
|
|
+ if (!command_buffer_.empty()) command_buffer_.pop_back();
|
|
|
+ if (drawing_area_) drawing_area_->queue_draw();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Simple character input
|
|
|
+ if (key_name.length() == 1 && !is_control && !is_lumacs_meta) {
|
|
|
+ command_buffer_ += key_name;
|
|
|
+ if (drawing_area_) drawing_area_->queue_draw();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If it's a control key (like C-n, C-p in minibuffer), we might want to pass it through
|
|
|
+ // or handle it (history navigation). For now, pass through if not handled above?
|
|
|
+ // Or strictly consume? TUI consumed everything. Let's strictly consume printable.
|
|
|
+ // But we want to allow C-q etc? No, minibuffer usually modal.
|
|
|
+ // We'll return true to consume unless we want to allow global keys.
|
|
|
+ return true;
|
|
|
}
|
|
|
+
|
|
|
+ // 4. Normal Mode Processing (Pass to Lua)
|
|
|
+ if (is_control && key_name.length() == 1) key_name = "C-" + key_name;
|
|
|
+ if (is_lumacs_meta) key_name = "M-" + key_name; // Use combined meta/alt
|
|
|
|
|
|
- std::cout << "Key pressed: " << key_name << std::endl; // Debug print
|
|
|
+ // std::cout << "Key: " << key_name << std::endl;
|
|
|
core_->lua_api()->process_key(key_name);
|
|
|
return true;
|
|
|
}
|