cursor_blink.hpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. #pragma once
  2. #include <chrono>
  3. namespace lumacs {
  4. /// @brief Shared cursor blinking logic for both GTK and TUI frontends.
  5. ///
  6. /// This utility encapsulates the cursor blinking algorithm:
  7. /// - Cursor is always visible for a threshold period after movement
  8. /// - After the threshold, cursor blinks on/off at a fixed interval
  9. class CursorBlinkController {
  10. public:
  11. /// Default blink interval (500ms on, 500ms off)
  12. static constexpr std::chrono::milliseconds BLINK_INTERVAL{500};
  13. /// Time cursor stays visible after movement before blinking starts
  14. static constexpr std::chrono::milliseconds STATIONARY_THRESHOLD{1000};
  15. CursorBlinkController() = default;
  16. /// @brief Notify the controller that the cursor has moved.
  17. /// This resets the blink timer and makes the cursor visible.
  18. void notify_cursor_moved() {
  19. last_move_time_ = std::chrono::steady_clock::now();
  20. visible_ = true;
  21. }
  22. /// @brief Update the blink state based on elapsed time.
  23. /// @return true if the visibility state changed (requires redraw)
  24. bool update() {
  25. auto now = std::chrono::steady_clock::now();
  26. auto since_move = std::chrono::duration_cast<std::chrono::milliseconds>(
  27. now - last_move_time_);
  28. // Cursor stays visible during stationary threshold
  29. if (since_move < STATIONARY_THRESHOLD) {
  30. if (!visible_) {
  31. visible_ = true;
  32. return true; // State changed
  33. }
  34. return false;
  35. }
  36. // After threshold, blink based on interval
  37. auto blink_phase = std::chrono::duration_cast<std::chrono::milliseconds>(
  38. now - last_move_time_ - STATIONARY_THRESHOLD);
  39. bool should_be_visible = (blink_phase.count() / BLINK_INTERVAL.count()) % 2 == 0;
  40. if (visible_ != should_be_visible) {
  41. visible_ = should_be_visible;
  42. return true; // State changed
  43. }
  44. return false;
  45. }
  46. /// @brief Check if the cursor should currently be visible.
  47. [[nodiscard]] bool is_visible() const { return visible_; }
  48. /// @brief Force cursor to be visible (useful for input events).
  49. void force_visible() {
  50. visible_ = true;
  51. last_move_time_ = std::chrono::steady_clock::now();
  52. }
  53. private:
  54. std::chrono::steady_clock::time_point last_move_time_ = std::chrono::steady_clock::now();
  55. bool visible_ = true;
  56. };
  57. } // namespace lumacs