File: scroller.cc

package info (click to toggle)
crawl 2%3A0.34.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 100,188 kB
  • sloc: cpp: 363,709; ansic: 27,765; javascript: 9,516; python: 8,463; perl: 3,293; java: 3,132; xml: 2,380; makefile: 1,835; sh: 611; objc: 250; cs: 15; sed: 9; lisp: 3
file content (212 lines) | stat: -rw-r--r-- 6,402 bytes parent folder | download | duplicates (2)
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/**
 * @file
 * @brief Formatted scroller
**/

#include "AppHdr.h"

#include "scroller.h"
#include "stringutil.h"

using namespace ui;

static vector<formatted_scroller*> open_scrollers;
static bool from_webtiles;

void formatted_scroller::add_formatted_string(const formatted_string& fs, bool new_line)
{
    contents += fs;
    if (new_line)
        contents.cprintf("\n");
    m_contents_dirty = true;
}

void formatted_scroller::add_text(const string& s, bool new_line)
{
    add_formatted_string(formatted_string::parse_string(s), new_line);
}

void formatted_scroller::add_raw_text(const string& s, bool new_line)
{
    contents.cprintf("%s%s", s.c_str(), new_line ? "\n" : "");
    m_contents_dirty = true;
}

class UIHookedScroller : public Scroller
{
public:
    UIHookedScroller(formatted_scroller &_fs) : Scroller(), fs(_fs) {};
    virtual void set_scroll(int y) override {
        if (y == m_scroll)
            return;
#ifdef USE_TILE_WEB
        tiles.json_open_object();
        tiles.json_write_bool("from_webtiles", from_webtiles);
        tiles.json_write_int("scroll", y);
        tiles.ui_state_change("formatted-scroller", 1);
#endif
        Scroller::set_scroll(y);
    };
protected:
    formatted_scroller &fs;
};

void formatted_scroller::scroll_to_end()
{
    // this needs to match the value in ui-layout.js scroller_scroll_to_line
    // (TODO: why?)
    m_scroll = numeric_limits<int32_t>::max();
    m_scroll_dirty = true;
}

int formatted_scroller::show()
{
    auto vbox = make_shared<Box>(Widget::VERT);
    vbox->set_cross_alignment(Widget::Align::STRETCH);

    if (!m_title.empty())
    {
        shared_ptr<Text> title = make_shared<Text>();
        title->set_text(m_title);
        title->set_margin_for_crt(0, 0, 1, 0);
        title->set_margin_for_sdl(0, 0, 20, 0);
        auto title_hbox = make_shared<Box>(Widget::HORZ);
#ifdef USE_TILE_LOCAL
        title_hbox->set_main_alignment(Widget::Align::CENTER);
#endif
        title_hbox->add_child(std::move(title));
        vbox->add_child(std::move(title_hbox));
    }

#ifdef USE_TILE_LOCAL
    if (!(m_flags & FS_PREWRAPPED_TEXT))
        vbox->max_size().width = tiles.get_crt_font()->char_width()*80;
#endif

    m_scroller = make_shared<UIHookedScroller>(*this);
#ifndef USE_TILE_LOCAL // ensure CRT scroller uses full height
    m_scroller->expand_v = true;
#endif
    auto text = make_shared<Text>();
    formatted_string c = formatted_string::parse_string(contents.to_colour_string(LIGHTGRAY));
    text->set_text(c);
    text->set_highlight_pattern(highlight, true);
    text->set_wrap_text(!(m_flags & FS_PREWRAPPED_TEXT));
    m_scroller->set_child(text);
    vbox->add_child(m_scroller);

    if (!m_more.empty())
    {
        shared_ptr<Text> more = make_shared<Text>();
        more = make_shared<Text>();
        more->set_text(m_more);
        more->set_margin_for_crt(1, 0, 0, 0);
        more->set_margin_for_sdl(20, 0, 0, 0);
        vbox->add_child(std::move(more));
    }

    auto popup = make_shared<ui::Popup>(vbox);

    m_contents_dirty = false;
    bool done = false;
    popup->on_keydown_event([&done, &text, this](const KeyEvent& ev) {
        m_lastch = ev.key();
        const maybe_bool pkey_result = process_key(m_lastch);
        // done = !process_key(m_lastch);
        if (m_contents_dirty)
        {
            m_contents_dirty = false;
            text->set_text(contents);
#ifdef USE_TILE_WEB
            tiles.json_open_object();
            tiles.json_write_string("text", contents.to_colour_string(LIGHTGRAY));
            tiles.json_write_string("highlight", highlight);
            tiles.ui_state_change("formatted-scroller", 0);
#endif
        }
        if (m_scroll_dirty)
        {
            m_scroll_dirty = false;
            m_scroller->set_scroll(m_scroll);
        }
        if (!pkey_result)
            return done = true;
        else if (pkey_result == maybe_bool::maybe)
        {
            if (m_scroller->on_event(ev))
                return true;
            // only check easy exit if `process_key` hasn't intercepted the key
            if (m_flags & FS_EASY_EXIT)
                return done = true;
        }
        // key either not processed at all, or `process_key` returned true
        return true;
    });

#ifdef USE_TILE_WEB
    tiles.json_open_object();
    tiles.json_write_string("tag", m_tag);
    tiles.json_write_string("text", contents.to_colour_string(LIGHTGRAY));
    tiles.json_write_string("highlight", highlight);
    tiles.json_write_string("more", m_more.to_colour_string(LIGHTGRAY));
    tiles.json_write_string("title", m_title.to_colour_string(LIGHTGRAY));
    tiles.json_write_bool("easy_exit", m_flags & FS_EASY_EXIT);
    tiles.json_write_bool("start_at_end", m_flags & FS_START_AT_END);
    tiles.push_ui_layout("formatted-scroller", 2);
    popup->on_layout_pop([](){ tiles.pop_ui_layout(); });
#endif

    if (m_flags & FS_START_AT_END)
        scroll_to_end();

    open_scrollers.push_back(this);
    if (m_scroll_dirty)
    {
        m_scroll_dirty = false;
        m_scroller->set_scroll(m_scroll);
    }

    ui::run_layout(std::move(popup), done);
    open_scrollers.pop_back();

    return m_lastch;
}

// true: key was processed, keep UI open
// false: key was processed, close UI
// maybe: key was not processed
// (the polarity is awkwardly opposite how this is used and derived here, but
// we keep it this way because all process_key functions in crawl have the
// same meanings for T/F)
maybe_bool formatted_scroller::process_key(int ch)
{
    // most keyhandling is in the scroller event handling, not here
    return ui::key_exits_popup(ch, true) ? false : maybe_bool::maybe;
}

void formatted_scroller::set_scroll(int y)
{
    if (from_webtiles)
        m_scroller->set_scroll(y);
    else
    {
        m_scroll = y;
        m_scroll_dirty = true;
    }
}

#ifdef USE_TILE_WEB
void recv_formatted_scroller_scroll(int line)
{
    if (open_scrollers.size() == 0)
        return;
    formatted_scroller *scroller = open_scrollers.back();
    from_webtiles = true;
    scroller->set_scroll(line);
    from_webtiles = false;
    // XXX: since the scroll event from webtiles is not delivered by the event
    // pumping loop in ui::pump_events, the UI system won't automatically draw
    // any changes for console spectators, so we need to force a redraw here.
    ui::force_render();
}
#endif