Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / commits / 08b4215

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz

Fixed cmdline input for vim With Claude

Christian Immanuel · 2026-06-06 15:11 · 08b421597ccceb3eb2b1f1fd35c1a01390ccf71d

 src/core/game.cpp               |   2 +-
 src/rendering/gl_renderer.cpp   |  24 +++++++++
 src/rendering/gl_renderer.hpp   |   5 +-
 src/states/game_state.cpp       |  43 ++++++++++------
 src/states/game_state.hpp       |   6 +--
 src/states/istate.hpp           |   4 +-
 src/states/menu_state.cpp       |   2 +-
 src/states/menu_state.hpp       |   6 +--
 src/systems/wall_connection.cpp |  72 +++++++++++++++++++++-----
 src/systems/wall_connection.hpp |  15 ++++--
 src/text_3d/vim_buffer.hpp      | 109 ++++++++++++++++++++++++++--------------
 11 files changed, 208 insertions(+), 80 deletions(-)

diff --git a/src/core/game.cpp b/src/core/game.cpp
index adeae78..871e286 100644
--- a/src/core/game.cpp
+++ b/src/core/game.cpp
@@ -72,7 +72,7 @@ Game::handle_Event(const SDL_Event& event)
 void
 Game::update(double dt_ns)
 {
-    if (m_state) m_state->update(dt_ns * 1e-9);
+    if (m_state) m_state->update(dt_ns * 1e-9, _gl_renderer.get());
 }
 
 
diff --git a/src/rendering/gl_renderer.cpp b/src/rendering/gl_renderer.cpp
index 0e149d3..fb9a861 100644
--- a/src/rendering/gl_renderer.cpp
+++ b/src/rendering/gl_renderer.cpp
@@ -631,6 +631,13 @@ GlRenderer::end_Frame(SDL_Window* window)
     }
 }
 
+
+void
+GlRenderer::clear_Depth()
+{
+    glClear(GL_DEPTH_BUFFER_BIT);
+}
+
 // ─────────────────────────────────────────────────────────────────────────────
 // Uniform setters
 // ─────────────────────────────────────────────────────────────────────────────
@@ -721,6 +728,23 @@ GlRenderer::set_FaceShade(float r, float g, float b, float back_dim, bool use_fr
 }
 
 
+void
+GlRenderer::set_DepthTest(bool on)
+{
+    if (on) glEnable (GL_DEPTH_TEST);
+    else    glDisable(GL_DEPTH_TEST);
+}
+
+
+void GlRenderer::set_CullBack(bool on)
+{
+    if (on) { glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); }
+    else      glDisable(GL_CULL_FACE);
+}
+
+/////////////////
+/// DRAW
+
 void
 GlRenderer::draw_Crosshair_()
 {
diff --git a/src/rendering/gl_renderer.hpp b/src/rendering/gl_renderer.hpp
index 465dc99..d45c782 100644
--- a/src/rendering/gl_renderer.hpp
+++ b/src/rendering/gl_renderer.hpp
@@ -155,8 +155,8 @@ public:
     bool init(SDL_Window* window);
     void begin_Frame(int viewport_w, int viewport_h);
     void end_Frame(SDL_Window* window);
+    void clear_Depth();
 
-    // ── Shader uniform setters ────────────────────────────────────────────────
     void set_MVP       (const Mat4& model, const Mat4& mvp);
     void set_NormalMat (const Mat4& model);
     void set_Color     (float  r, float  g, float  b);
@@ -169,10 +169,13 @@ public:
     void set_Emissive  (float r, float g, float b, float strength);
     void set_BloomStrength  (float s) { _bloom_strength = s; }
     void set_Crosshair(bool on) { _crosshair_enabled = on; }
+    void set_DepthTest(bool on);
+    void set_CullBack (bool on);
 
     void enable_MandelbrotMode(bool on);
     void enable_WallPaperMode (bool on);
 
+    float       fov_y()      const { return SDL_PI_F / 3.0f; }
     float       aspect()     const;
     const Mat4& projection() const;
 
diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp
index d7d86e8..f0d6240 100644
--- a/src/states/game_state.cpp
+++ b/src/states/game_state.cpp
@@ -561,17 +561,32 @@ GameState::handle_Input(FrameInput& input, double dt) {
             case InputCommand::ConnectPultExit:   on_WallConnectExit();   break;
         }
     }
+
     if (_wall_connection.target() == WallConnection::Target::Editor) {
         WallConnection::Request req = _wall_connection.feed_Vim(input.vim_keys, _ctx.camera->pos.y);
         input.vim_keys.clear();
-        if (req == WallConnection::Request::Exit) {
-            editor_CommitToWall(_wall_connection.lines());
-            _wall_connection.end();
-            _frame_input.capture_vim = false;
-        }
-        else if (req == WallConnection::Request::EditorWrite) {
-            editor_CommitToWall(_wall_connection.lines());
-            _wall_connection.load_Editor(editor_AbsorbLines(), _ctx.camera->pos.y);
+        switch (req) {
+            case WallConnection::Request::Write:
+                editor_CommitToWall(_wall_connection.lines());
+                _wall_connection.mark_Saved();
+                break;
+            case WallConnection::Request::WriteQuit:
+                editor_CommitToWall(_wall_connection.lines());
+                _wall_connection.end();
+                _frame_input.capture_vim = false;
+                break;
+            case WallConnection::Request::Exit:
+                editor_CommitToWall(_wall_connection.lines());
+                _wall_connection.end();
+                _frame_input.capture_vim = false;
+                break;
+            case WallConnection::Request::QuitDiscard:
+                editor_CommitToWall(_wall_connection.lines());
+                _wall_connection.end();
+                _frame_input.capture_vim = false;
+                break;
+            case WallConnection::Request::None:
+                break;
         }
     }
     else if (_wall_connection.target() == WallConnection::Target::Program) {
@@ -603,7 +618,7 @@ GameState::update_PlayerCamera(FrameInput& input, double dt)
 }
 
 void
-GameState::update(double dt)
+GameState::update(double dt, const GlRenderer* gl)
 {
     FrameInput& input = _frame_input;
 
@@ -637,7 +652,7 @@ GameState::update(double dt)
         _plate_sys-> update(dt, *_ctx.player, _level_director->step_Plates());
         _editor_wall.update(dt, _ctx.camera->pos);
 
-        _wall_connection.update(dt);
+        _wall_connection.update(dt, *_ctx.camera, gl->aspect(), gl->fov_y());
     }
 
 
@@ -720,10 +735,6 @@ GameState::render(SDL_Window& window, GlRenderer& renderer)
             lbl.draw(renderer, *_ctx.camera, *_ctx.light);
     }
 
-    { FP_ZONE("render.wall_edit");
-        _wall_connection.render(renderer, *_ctx.camera, *_ctx.light);
-    }
-
     { FP_ZONE("render._carried");
         DynArray<CarriedWordNode*> nodes = _carried.nodes();
         for (const CarriedWordNode* node : nodes)
@@ -761,6 +772,10 @@ GameState::render(SDL_Window& window, GlRenderer& renderer)
         _celebration_sys->draw(renderer, *_ctx.camera, *_ctx.light);
     }
 
+    { FP_ZONE("render.wall_edit");
+        _wall_connection.render(renderer, *_ctx.camera, *_ctx.light);
+    }
+
     { FP_ZONE("render.end_Frame"); renderer.end_Frame(&window); }
 }
 
diff --git a/src/states/game_state.hpp b/src/states/game_state.hpp
index 16e8b1a..fa84f45 100644
--- a/src/states/game_state.hpp
+++ b/src/states/game_state.hpp
@@ -137,7 +137,7 @@ class GameState : public IState
 public:
     explicit GameState    (size_t starting_level = 0);
             ~GameState    () = default;
-    void     handle_Event (Game&, const SDL_Event&)  override;
-    void     update       (double dt)                override;
-    void     render       (SDL_Window&, GlRenderer&) override;
+    void     handle_Event (Game&, const SDL_Event&)      override;
+    void     update       (double dt, const GlRenderer*) override;
+    void     render       (SDL_Window&, GlRenderer&)     override;
 };
diff --git a/src/states/istate.hpp b/src/states/istate.hpp
index 4579a93..bf8b062 100644
--- a/src/states/istate.hpp
+++ b/src/states/istate.hpp
@@ -14,6 +14,6 @@ public:
     virtual void on_Exit(Game&) {}
 
     virtual void handle_Event(Game& game, const SDL_Event&) = 0;
-    virtual void update(double dt) = 0;
-    virtual void render(SDL_Window&, GlRenderer&) = 0;
+    virtual void update(double dt, const GlRenderer*)       = 0;
+    virtual void render(SDL_Window&, GlRenderer&)           = 0;
 };
diff --git a/src/states/menu_state.cpp b/src/states/menu_state.cpp
index 0bba412..ed5e474 100644
--- a/src/states/menu_state.cpp
+++ b/src/states/menu_state.cpp
@@ -272,7 +272,7 @@ MenuState::pick_FromCrosshair() const
 
 
 void
-MenuState::update(double dt)
+MenuState::update(double dt, const GlRenderer*)
 {
     _t += dt;
 
diff --git a/src/states/menu_state.hpp b/src/states/menu_state.hpp
index a82866b..cf26887 100644
--- a/src/states/menu_state.hpp
+++ b/src/states/menu_state.hpp
@@ -50,7 +50,7 @@ class MenuState : public IState
 public:
     MenuState();
 
-    void handle_Event(Game&, const SDL_Event&)  override;
-    void update      (double dt)                override;
-    void render      (SDL_Window&, GlRenderer&) override;
+    void handle_Event(Game&, const SDL_Event&)       override;
+    void update      (double dt, const GlRenderer*)  override;
+    void render      (SDL_Window&, GlRenderer&)      override;
 };
diff --git a/src/systems/wall_connection.cpp b/src/systems/wall_connection.cpp
index fbf9732..23b2e63 100644
--- a/src/systems/wall_connection.cpp
+++ b/src/systems/wall_connection.cpp
@@ -93,14 +93,16 @@ WallConnection::feed_Vim(DynArray<int>& keys, double eye_y)
 
     Request req = Request::None;
     switch (_vim.take_Signal()) {
-        case VimBuffer::Signal::Exit:  return Request::Exit;
-        case VimBuffer::Signal::Write: req = Request::EditorWrite; break;
+        case VimBuffer::Signal::Exit:        return Request::Exit;
+        case VimBuffer::Signal::WriteQuit:   return Request::WriteQuit;
+        case VimBuffer::Signal::QuitDiscard: return Request::QuitDiscard;
+        case VimBuffer::Signal::Write:       req = Request::Write; break;
         case VimBuffer::Signal::Help:
             _status.clear();
             _status.push_back("-- VIM HELP --");
             _status.push_back("i a A o O  insert    Esc normal    h j k l move");
             _status.push_back("0 $  line ends   gg G :N  jump line   x dd  delete");
-            _status.push_back(":w write to wall   :exit leave   ctrl+WASD move");
+            _status.push_back(":w write   :q quit   :wq write+quit   :q! discard");
             break;
         default: break;
     }
@@ -178,7 +180,7 @@ WallConnection::rebuild_Editor()
         const std::string& s = lines[i];
         br.n_chars = s.size();
 
-        // Measure the full line (spaces included) for a faithful char width.
+       // Measure the full line (spaces included) for a faithful char width.
         const bool drawable = s.find_first_not_of(' ') != std::string::npos;
         if (drawable) {
             Text3dPtr meas = make_Text3d(s, Text3d::depth_wall, 0.003f, tf.position, ConfigColor::white);
@@ -261,6 +263,7 @@ WallConnection::rebuild_Editor()
     rebuild_Cmdline();
 }
 
+
 void
 WallConnection::rebuild_Cmdline()
 {
@@ -273,16 +276,45 @@ WallConnection::rebuild_Cmdline()
     else text = (_vim.mode() == VimBuffer::Mode::Insert) ? "-- INSERT --" : "-- NORMAL --";
     if (text.empty()) return;
 
-    const float ws = World::get_BoxScale();
-    Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, ws);
+    // Built at origin; render() places it at the eased _cmd_pos each frame.
+    _cmdline = make_Text3d(text, Text3d::depth_wall, 0.0016f, Vec3{0,0,0}, ConfigColor::white);
+}
 
-    Vec3 pos = tf.position;
-    pos.x += 0.8;
-    pos.y  = -static_cast<double>(ws) + 0.8;
-    pos.z  = 0.0;
 
-    _cmdline = make_Text3d(text, Text3d::depth_wall, 0.0028f, pos, ConfigColor::white);
-    _cmdline->yaw = tf.yaw;
+void
+WallConnection::update(double dt, const Camera& cam, float aspect, float fov_y)
+{
+    if (!active()) return;
+    _blink += dt;
+
+    const Vec3 up = Math::cross(cam.right, cam.fwd);
+
+    const double dist   = 2.2;
+    const double half_h = dist * static_cast<double>(SDL_tanf(fov_y * 0.5f));
+    const double half_w = half_h * static_cast<double>(aspect);
+
+    // Sit at a fraction of the way toward the lower-left corner. 0 = center,
+    // 1 = exactly the frustum edge (text would be clipped at the very corner),
+    // so keep a margin.
+    const double fx = 0.82;   // horizontal: 82% toward the left edge
+    const double fy = 0.78;   // vertical:   78% toward the bottom edge
+    const double left = half_w * fx;
+    const double down = half_h * fy;
+
+    Vec3 target {
+        cam.pos.x + cam.fwd.x * dist - cam.right.x * left - up.x * down,
+        cam.pos.y + cam.fwd.y * dist - cam.right.y * left - up.y * down,
+        cam.pos.z + cam.fwd.z * dist - cam.right.z * left - up.z * down,
+    };
+
+    if (!_cmd_pos_init) { _cmd_pos = target; _cmd_pos_init = true; }
+
+    const double k = 1.0 - SDL_exp(-6.0 * dt);
+    _cmd_pos.x += (target.x - _cmd_pos.x) * k;
+    _cmd_pos.y += (target.y - _cmd_pos.y) * k;
+    _cmd_pos.z += (target.z - _cmd_pos.z) * k;
+
+    _cmd_yaw   = static_cast<float>(SDL_atan2(-cam.fwd.x, -cam.fwd.z));
 }
 
 
@@ -300,7 +332,21 @@ WallConnection::render(GlRenderer& gl, const Camera& cam, const Light& light) co
             for (const Text3dPtr& t : er.toks)
                 if (t) t->draw(gl, cam, light);
         for (const Text3dPtr& n : _linenums) if (n) n->draw(gl, cam, light);
-        if (_cmdline) _cmdline->draw(gl, cam, light);
+
+        if (_cmdline) {
+            const double hw = static_cast<double>(_cmdline->half_extent);
+            _cmdline->pos = Vec3{
+                _cmd_pos.x + cam.right.x * hw,
+                _cmd_pos.y + cam.right.y * hw,
+                _cmd_pos.z + cam.right.z * hw,
+            };
+            _cmdline->yaw   = _cmd_yaw;
+            _cmdline->pitch = 0.0f;
+
+            gl.clear_Depth();
+            _cmdline->draw(gl, cam, light);
+        }
+
         draw_EditorCursor(gl, cam, light);
         draw_Electric    (gl, cam);
     }
diff --git a/src/systems/wall_connection.hpp b/src/systems/wall_connection.hpp
index df20388..48cbc00 100644
--- a/src/systems/wall_connection.hpp
+++ b/src/systems/wall_connection.hpp
@@ -25,7 +25,7 @@ class WallConnection
 {
 public:
     enum class Target  : uint8_t { None, Program, Editor };
-    enum class Request : uint8_t { None, Exit, EditorWrite };
+    enum class Request : uint8_t { None, Exit, Write, WriteQuit, QuitDiscard };
 
     bool   active() const { return _target != Target::None; }
     Target target() const { return _target; }
@@ -42,15 +42,19 @@ public:
     DynArray<std::string>
             lines   () const;
 
-    void update(double dt) { if (active()) _blink += dt; }
+    void update(double dt, const Camera& cam, float aspect, float fov_y);
     void render(GlRenderer& gl, const Camera& cam, const Light& light) const;
+    void mark_Saved() { _vim.mark_Saved(); }
 
 private:
+    bool     _cmd_pos_init { false };
     unsigned _vim_seen_version { 0 };
 
-    double _row0_y{ 0.0 };
-    double _eye_y { 0.0 };
-    double _blink { 0.0 };
+    float  _cmd_pitch { 0.0f };
+    float  _cmd_yaw { 0.0f };
+    double _row0_y  { 0.0 };
+    double _eye_y   { 0.0 };
+    double _blink   { 0.0 };
     double _code_left_z { 0.0 };
 
     Target _target{ Target::None };
@@ -58,6 +62,7 @@ private:
     Text3dPtr _cmdline;
     Text3dPtr _prog_input;
 
+    Vec3 _cmd_pos {};
     Vec3 _pult_pos{};
 
     std::string _prog_last;
diff --git a/src/text_3d/vim_buffer.hpp b/src/text_3d/vim_buffer.hpp
index d8f4d39..a9dd8d2 100644
--- a/src/text_3d/vim_buffer.hpp
+++ b/src/text_3d/vim_buffer.hpp
@@ -8,7 +8,14 @@
 class VimBuffer {
 public:
     enum class Mode   : uint8_t { Normal, Insert, Command };
-    enum class Signal : uint8_t { None, Exit, Help, Write };
+        enum class Signal : uint8_t {
+        None,
+        Exit,
+        Help,
+        Write,
+        WriteQuit,
+        QuitDiscard
+    };
 
     void load(const std::vector<std::string>& src) {
         _lines = src;
@@ -16,8 +23,11 @@ public:
         _row = _col = 0; _mode = Mode::Normal;
         _count = 0; _pending.clear(); _cmd.clear(); _status.clear();
         _sig = Signal::None; ++_version;
+        _saved = _lines;
+        _dirty = false;
     }
 
+
     void key_char(char c) {
         if      (_mode == Mode::Insert)  { insert_Char(c); }
         else if (_mode == Mode::Command) { _cmd.push_back(c); touch(); }
@@ -51,17 +61,22 @@ public:
     const std::string& cmdline()  const { return _cmd; }
     const std::string& status()   const { return _status; }
     Signal take_Signal() { Signal s = _sig; _sig = Signal::None; return s; }
+    void mark_Saved() { _saved = _lines; _dirty = false; touch(); }
 
 private:
-    std::vector<std::string> _lines { "" };
+    bool     _dirty = false;
+    unsigned _version = 0;
     int      _row = 0, _col = 0;
-    Mode     _mode = Mode::Normal;
     int      _count = 0;
-    std::string _pending; // "d" or "g" awaiting second key
-    std::string _cmd;     // command-line text (":...")
+
+    std::string _pending;
+    std::string _cmd;
     std::string _status;
+
+    Mode     _mode = Mode::Normal;
     Signal   _sig = Signal::None;
-    unsigned _version = 0;
+    std::vector<std::string> _saved;
+    std::vector<std::string> _lines { "" };
 
     void touch() { ++_version; }
     int  lineLen() const { return (int)_lines[(size_t)_row].size(); }
@@ -73,29 +88,6 @@ private:
     }
     int  eff() const { return _count > 0 ? _count : 1; }
 
-    void insert_Char(char c) {
-        std::string& L = _lines[(size_t)_row];
-        if (_col > (int)L.size()) _col = (int)L.size();
-        L.insert((size_t)_col, 1, c); ++_col; touch();
-    }
-    void split_Line() {
-        std::string& L = _lines[(size_t)_row];
-        std::string tail = L.substr((size_t)_col);
-        L.erase((size_t)_col);
-        _lines.insert(_lines.begin() + _row + 1, tail);
-        ++_row; _col = 0; touch();
-    }
-    void backspace_Insert() {
-        if (_col > 0) { _lines[(size_t)_row].erase((size_t)(_col-1), 1); --_col; }
-        else if (_row > 0) {
-            int prevlen = (int)_lines[(size_t)(_row-1)].size();
-            _lines[(size_t)(_row-1)] += _lines[(size_t)_row];
-            _lines.erase(_lines.begin() + _row);
-            --_row; _col = prevlen;
-        }
-        touch();
-    }
-
     void normal_Key(char c) {
         if (c == ':') { _mode = Mode::Command; _cmd = ":"; _status.clear(); touch(); return; }
 
@@ -135,28 +127,68 @@ private:
         _count = 0; clampCol(); touch();
     }
 
+    void insert_Char(char c) {
+        std::string& L = _lines[(size_t)_row];
+        if (_col > (int)L.size()) _col = (int)L.size();
+        L.insert((size_t)_col, 1, c); ++_col; _dirty = true; touch();
+    }
+    void split_Line() {
+        std::string& L = _lines[(size_t)_row];
+        std::string tail = L.substr((size_t)_col);
+        L.erase((size_t)_col);
+        _lines.insert(_lines.begin() + _row + 1, tail);
+        ++_row; _col = 0; _dirty = true; touch();
+    }
+    void backspace_Insert() {
+        if (_col > 0) { _lines[(size_t)_row].erase((size_t)(_col-1), 1); --_col; _dirty = true; }
+        else if (_row > 0) {
+            int prevlen = (int)_lines[(size_t)(_row-1)].size();
+            _lines[(size_t)(_row-1)] += _lines[(size_t)_row];
+            _lines.erase(_lines.begin() + _row);
+            --_row; _col = prevlen; _dirty = true;
+        }
+        touch();
+    }
     void delete_Chars(int n) {
         std::string& L = _lines[(size_t)_row];
-        for (int i = 0; i < n && _col < (int)L.size(); ++i) L.erase((size_t)_col, 1);
+        for (int i = 0; i < n && _col < (int)L.size(); ++i) { L.erase((size_t)_col, 1); _dirty = true; }
         clampCol();
     }
     void delete_Lines(int n) {
         for (int i = 0; i < n && (int)_lines.size() > 0; ++i) {
-            if (_lines.size() == 1) { _lines[0].clear(); break; }
+            if (_lines.size() == 1) { _lines[0].clear(); _dirty = true; break; }
             _lines.erase(_lines.begin() + _row);
             if (_row >= (int)_lines.size()) _row = (int)_lines.size() - 1;
+            _dirty = true;
         }
         clampCol();
     }
-    void open_Below() { _lines.insert(_lines.begin() + _row + 1, ""); ++_row; _col = 0; }
-    void open_Above() { _lines.insert(_lines.begin() + _row,     ""); _col = 0; }
+    void open_Below() { _lines.insert(_lines.begin() + _row + 1, ""); ++_row; _col = 0; _dirty = true; }
+    void open_Above() { _lines.insert(_lines.begin() + _row,     ""); _col = 0; _dirty = true; }
 
     void run_Command() {
-        std::string c = _cmd.size() ? _cmd.substr(1) : "";   // strip ':'
+        std::string c = _cmd.size() ? _cmd.substr(1) : "";
         _cmd.clear(); _mode = Mode::Normal;
-        if      (c == "exit" || c == "q" || c == "q!") _sig = Signal::Exit;
-        else if (c == "help")                          _sig = Signal::Help;
-        else if (c == "w" || c == "write")             _sig = Signal::Write;
+
+        if (c == "w" || c == "write") {
+            _sig = Signal::Write;
+        }
+        else if (c == "wq" || c == "x") {
+            _sig = Signal::WriteQuit;
+        }
+        else if (c == "q" || c == "quit") {
+            if (_dirty) {
+                _status = "No write since last change (add ! to override)";
+            } else {
+                _sig = Signal::Exit;
+            }
+        }
+        else if (c == "q!" || c == "quit!") {
+            _lines = _saved;
+            _row = clampRow(_row); clampCol();
+            _dirty = false;
+            _sig = Signal::QuitDiscard;
+        }
         else if (!c.empty() && std::all_of(c.begin(), c.end(),
                  [](char ch){ return std::isdigit((unsigned char)ch); })) {
             _row = clampRow(std::stoi(c) - 1); clampCol();
@@ -165,4 +197,7 @@ private:
         touch();
     }
     void cancel_Command() { _cmd.clear(); _mode = Mode::Normal; touch(); }
+
+    bool dirty() const { return _dirty; }
+
 };