|
22 | 22 | #include <algorithm> |
23 | 23 | #include <cstdlib> |
24 | 24 | #include <iostream> |
| 25 | +#include <thread> |
25 | 26 |
|
26 | 27 | #if defined(EMSCRIPTEN) |
27 | 28 | # include <emscripten/emscripten.h> |
@@ -553,6 +554,21 @@ void Screen::initialize(GLFWwindow *window, bool shutdown_glfw) { |
553 | 554 | /// Fixes retina display-related font rendering issue (#185) |
554 | 555 | nvgBeginFrame(m_nvg_context, m_size[0], m_size[1], m_pixel_ratio); |
555 | 556 | nvgEndFrame(m_nvg_context); |
| 557 | + |
| 558 | + m_tooltip_redraw_notify_thread = new std::thread([this]() { |
| 559 | + while (true) { |
| 560 | + std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
| 561 | + if (glfwWindowShouldClose(m_glfw_window)) |
| 562 | + break; |
| 563 | + if (m_visible && m_last_run_mode == RunMode::Lazy) { |
| 564 | + double elapsed = glfwGetTime() - m_last_interaction; |
| 565 | + if (elapsed > m_tooltip_delay && m_tooltip_redraw_required) { |
| 566 | + m_tooltip_redraw_required = false; |
| 567 | + redraw(); |
| 568 | + } |
| 569 | + } |
| 570 | + } |
| 571 | + }); |
556 | 572 | } |
557 | 573 |
|
558 | 574 | Screen::~Screen() { |
@@ -582,6 +598,13 @@ Screen::~Screen() { |
582 | 598 |
|
583 | 599 | if (m_glfw_window && m_shutdown_glfw) |
584 | 600 | glfwDestroyWindow(m_glfw_window); |
| 601 | + |
| 602 | + if (m_tooltip_redraw_notify_thread) { |
| 603 | + std::thread *t = (std::thread *) m_tooltip_redraw_notify_thread; |
| 604 | + if (t->joinable()) |
| 605 | + t->join(); |
| 606 | + delete t; |
| 607 | + } |
585 | 608 | } |
586 | 609 |
|
587 | 610 | void Screen::set_visible(bool visible) { |
@@ -772,72 +795,76 @@ void Screen::nvg_flush() { |
772 | 795 |
|
773 | 796 | void Screen::draw_widgets() { |
774 | 797 | nvgBeginFrame(m_nvg_context, m_size[0], m_size[1], m_pixel_ratio); |
| 798 | + auto end_frame_guard = scope_guard([this] { nvgEndFrame(m_nvg_context); }); |
775 | 799 |
|
776 | 800 | draw(m_nvg_context); |
777 | 801 |
|
| 802 | + /* Draw tooltips */ |
| 803 | + const Widget *widget = find_widget(m_mouse_pos); |
| 804 | + while (widget && widget->tooltip().empty()) |
| 805 | + widget = widget->parent(); |
| 806 | + |
| 807 | + if (!widget || widget->tooltip().empty()) { |
| 808 | + m_tooltip_redraw_required = false; |
| 809 | + return; |
| 810 | + } |
| 811 | + |
778 | 812 | double elapsed = glfwGetTime() - m_last_interaction; |
779 | 813 |
|
780 | | - if (elapsed > 0.2f) { |
781 | | - /* Draw tooltips */ |
782 | | - const Widget *widget = find_widget(m_mouse_pos); |
783 | | - while (widget && widget->tooltip().empty()) |
784 | | - widget = widget->parent(); |
785 | | - |
786 | | - if (widget && !widget->tooltip().empty()) { |
787 | | - int tooltip_width = 180; |
788 | | - |
789 | | - float bounds[4]; |
790 | | - nvgFontFace(m_nvg_context, "sans"); |
791 | | - nvgFontSize(m_nvg_context, 15.0f); |
792 | | - nvgTextAlign(m_nvg_context, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); |
793 | | - nvgTextLineHeight(m_nvg_context, 1.1f); |
794 | | - Vector2i pos = widget->absolute_position() + |
795 | | - Vector2i(widget->width() / 2, widget->height() + 10); |
796 | | - |
797 | | - std::string_view tooltip = widget->tooltip(); |
798 | | - nvgTextBounds(m_nvg_context, pos.x(), pos.y(), |
799 | | - tooltip.data(), tooltip.data() + tooltip.size(), bounds); |
800 | | - |
801 | | - int h = (bounds[2] - bounds[0]) / 2; |
802 | | - if (h > tooltip_width / 2) { |
803 | | - nvgTextAlign(m_nvg_context, NVG_ALIGN_CENTER | NVG_ALIGN_TOP); |
804 | | - nvgTextBoxBounds(m_nvg_context, pos.x(), pos.y(), tooltip_width, |
805 | | - tooltip.data(), tooltip.data() + tooltip.size(), bounds); |
806 | | - |
807 | | - h = (bounds[2] - bounds[0]) / 2; |
808 | | - } |
809 | | - int shift = 0; |
810 | | - |
811 | | - if (pos.x() - h - 8 < 0) { |
812 | | - /* Keep tooltips on screen */ |
813 | | - shift = pos.x() - h - 8; |
814 | | - pos.x() -= shift; |
815 | | - bounds[0] -= shift; |
816 | | - bounds[2] -= shift; |
817 | | - } |
| 814 | + if (elapsed <= m_tooltip_delay) { |
| 815 | + m_tooltip_redraw_required = true; |
| 816 | + } else { |
| 817 | + int tooltip_width = 180; |
| 818 | + |
| 819 | + float bounds[4]; |
| 820 | + nvgFontFace(m_nvg_context, "sans"); |
| 821 | + nvgFontSize(m_nvg_context, 15.0f); |
| 822 | + nvgTextAlign(m_nvg_context, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); |
| 823 | + nvgTextLineHeight(m_nvg_context, 1.1f); |
| 824 | + Vector2i pos = widget->absolute_position() + |
| 825 | + Vector2i(widget->width() / 2, widget->height() + 10); |
| 826 | + |
| 827 | + std::string_view tooltip = widget->tooltip(); |
| 828 | + nvgTextBounds(m_nvg_context, pos.x(), pos.y(), |
| 829 | + tooltip.data(), tooltip.data() + tooltip.size(), bounds); |
| 830 | + |
| 831 | + int h = (bounds[2] - bounds[0]) / 2; |
| 832 | + if (h > tooltip_width / 2) { |
| 833 | + nvgTextAlign(m_nvg_context, NVG_ALIGN_CENTER | NVG_ALIGN_TOP); |
| 834 | + nvgTextBoxBounds(m_nvg_context, pos.x(), pos.y(), tooltip_width, |
| 835 | + tooltip.data(), tooltip.data() + tooltip.size(), bounds); |
| 836 | + |
| 837 | + h = (bounds[2] - bounds[0]) / 2; |
| 838 | + } |
| 839 | + int shift = 0; |
| 840 | + |
| 841 | + if (pos.x() - h - 8 < 0) { |
| 842 | + /* Keep tooltips on screen */ |
| 843 | + shift = pos.x() - h - 8; |
| 844 | + pos.x() -= shift; |
| 845 | + bounds[0] -= shift; |
| 846 | + bounds[2] -= shift; |
| 847 | + } |
818 | 848 |
|
819 | | - nvgGlobalAlpha(m_nvg_context, 0.8f); |
| 849 | + nvgGlobalAlpha(m_nvg_context, 0.8f); |
820 | 850 |
|
821 | | - nvgBeginPath(m_nvg_context); |
822 | | - nvgFillColor(m_nvg_context, Color(0, 255)); |
823 | | - nvgRoundedRect(m_nvg_context, bounds[0] - 4 - h, bounds[1] - 4, |
824 | | - (int) (bounds[2] - bounds[0]) + 8, |
825 | | - (int) (bounds[3] - bounds[1]) + 8, 3); |
| 851 | + nvgBeginPath(m_nvg_context); |
| 852 | + nvgFillColor(m_nvg_context, Color(0, 255)); |
| 853 | + nvgRoundedRect(m_nvg_context, bounds[0] - 4 - h, bounds[1] - 4, |
| 854 | + (int) (bounds[2] - bounds[0]) + 8, |
| 855 | + (int) (bounds[3] - bounds[1]) + 8, 3); |
826 | 856 |
|
827 | | - int px = (int) ((bounds[2] + bounds[0]) / 2) - h + shift; |
828 | | - nvgMoveTo(m_nvg_context, px, bounds[1] - 10); |
829 | | - nvgLineTo(m_nvg_context, px + 7, bounds[1] + 1); |
830 | | - nvgLineTo(m_nvg_context, px - 7, bounds[1] + 1); |
831 | | - nvgFill(m_nvg_context); |
| 857 | + int px = (int) ((bounds[2] + bounds[0]) / 2) - h + shift; |
| 858 | + nvgMoveTo(m_nvg_context, px, bounds[1] - 10); |
| 859 | + nvgLineTo(m_nvg_context, px + 7, bounds[1] + 1); |
| 860 | + nvgLineTo(m_nvg_context, px - 7, bounds[1] + 1); |
| 861 | + nvgFill(m_nvg_context); |
832 | 862 |
|
833 | | - nvgFillColor(m_nvg_context, Color(255, 255)); |
834 | | - nvgFontBlur(m_nvg_context, 0.0f); |
835 | | - nvgTextBox(m_nvg_context, pos.x() - h, pos.y(), tooltip_width, |
836 | | - tooltip.data(), tooltip.data() + tooltip.size()); |
837 | | - } |
| 863 | + nvgFillColor(m_nvg_context, Color(255, 255)); |
| 864 | + nvgFontBlur(m_nvg_context, 0.0f); |
| 865 | + nvgTextBox(m_nvg_context, pos.x() - h, pos.y(), tooltip_width, |
| 866 | + tooltip.data(), tooltip.data() + tooltip.size()); |
838 | 867 | } |
839 | | - |
840 | | - nvgEndFrame(m_nvg_context); |
841 | 868 | } |
842 | 869 |
|
843 | 870 | bool Screen::keyboard_event(int key, int scancode, int action, int modifiers) { |
@@ -1128,15 +1155,6 @@ void Screen::move_window_to_front(Window *window) { |
1128 | 1155 | } while (changed); |
1129 | 1156 | } |
1130 | 1157 |
|
1131 | | -bool Screen::tooltip_fade_in_progress() const { |
1132 | | - double elapsed = glfwGetTime() - m_last_interaction; |
1133 | | - if (elapsed < 0.25f || elapsed > 1.25f) |
1134 | | - return false; |
1135 | | - /* Temporarily increase the frame rate to fade in the tooltip */ |
1136 | | - const Widget *widget = find_widget(m_mouse_pos); |
1137 | | - return widget && !widget->tooltip().empty(); |
1138 | | -} |
1139 | | - |
1140 | 1158 | #if defined(NANOGUI_USE_OPENGL) || defined(NANOGUI_USE_GLES) |
1141 | 1159 | uint32_t Screen::framebuffer_handle() const { |
1142 | 1160 | return applies_color_management() ? m_color_pass->framebuffer_handle() : 0; |
|
0 commit comments