baseplate.ui.cpp

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <planet/telemetry/rate.hpp>
#include <planet/ui/baseplate.hpp>
#include <planet/ui/widget.hpp>

#include <planet/log.hpp>


namespace {
    planet::telemetry::exponential_decay c_widget_list_length{
            "planet_ui_baseplate_widget_count", 20};
    planet::telemetry::exponential_decay c_hover_list_length{
            "planet_ui_baseplate_hover_count", 5};
}


planet::ui::baseplate::~baseplate() {
    if (not widgets.empty()) {
        planet::log::warning(
                "Baseplate still has", widgets.size(),
                "widgets attached to it");
        for (auto w : widgets) { w->baseplate = nullptr; }
    }
}


void planet::ui::baseplate::start_frame_reset() {
    c_widget_list_length.add_measurement(widgets.size());

    // Hover handling
    auto const now = std::chrono::steady_clock::now();
    auto const elapsed = now - last_reset;
    last_reset = now;
    for (auto widget : widgets) {
        if (widget->contains_global_coordinate(last_mouse.location)) {
            widget->hover(widget->hover_time += elapsed);
            current_hovers.push_back(widget);
            std::erase(previous_hovers, widget);
        }
    }
    c_hover_list_length.add_measurement(current_hovers.size());
    for (auto widget : previous_hovers) {
        widget->hover(widget->hover_time = {});
    }
    previous_hovers.clear();
    std::swap(previous_hovers, current_hovers);

    // Widgets and focus
    if (soft_focus
        and std::find(widgets.begin(), widgets.end(), soft_focus)
                == widgets.end()) {
        soft_focus = nullptr;
    }
    if (hard_focus
        and std::find(widgets.begin(), widgets.end(), hard_focus)
                == widgets.end()) {
        hard_focus = nullptr;
    }
    widgets.clear();
}


void planet::ui::baseplate::add(widget_ptr const w) {
    w->baseplate = this;
    widgets.push_back(w);
}


auto planet::ui::baseplate::forward_mouse() -> task_type {
    try {
        auto mouse = events.mouse.values();
        while (true) {
            last_mouse = co_await mouse.next();
            // Look for the widget that should now have soft focus
            soft_focus = nullptr;
            for (widget_ptr w : widgets) {
                if (w->wants_focus()
                    and (not soft_focus or soft_focus->z_layer < w->z_layer)
                    and w->contains_global_coordinate(last_mouse.location)) {
                    soft_focus = w;
                }
            }
            // Now send the event to the correct widget
            if (auto *send_to = find_focused_widget(); send_to) {
                send_to->events.mouse.push(last_mouse);
            }
        }
    } catch (std::exception const &e) {
        log::critical("Baseplate mouse forwarding exception", e.what());
    }
}
auto planet::ui::baseplate::forward_keys() -> task_type {
    try {
        auto key = events.key.values();
        while (true) {
            auto const k = co_await key.next();
            if (auto *send_to = find_focused_widget(); send_to) {
                send_to->events.key.push(k);
            }
        }
    } catch (std::exception const &e) {
        log::critical("Baseplate key forwarding exception", e.what());
    }
}
auto planet::ui::baseplate::forward_scroll() -> task_type {
    try {
        auto scroll = events.scroll.values();
        while (true) {
            auto const s = co_await scroll.next();
            if (auto *send_to = find_focused_widget(); send_to) {
                send_to->events.scroll.push(s);
            }
        }
    } catch (std::exception const &e) {
        log::critical("Baseplate scroll forwarding exception", e.what());
    }
}