[mouse] breathe some life back into mouse support

master
Tim Stack 1 month ago
parent 7fa4e25318
commit 7341dc1f1a

@ -38,6 +38,7 @@ breadcrumb_curses::breadcrumb_curses()
{
this->bc_match_search_overlay.sos_parent = this;
this->bc_match_source.set_reverse_selection(true);
this->bc_match_view.set_title("breadcrumb popup");
this->bc_match_view.set_selectable(true);
this->bc_match_view.set_overlay_source(&this->bc_match_search_overlay);
this->bc_match_view.set_sub_source(&this->bc_match_source);
@ -47,11 +48,11 @@ breadcrumb_curses::breadcrumb_curses()
this->add_child_view(&this->bc_match_view);
}
void
bool
breadcrumb_curses::do_update()
{
if (!this->bc_line_source) {
return;
return false;
}
size_t crumb_index = 0;
@ -94,12 +95,14 @@ breadcrumb_curses::do_update()
line_range lr{0, static_cast<int>(width)};
view_curses::mvwattrline(
this->bc_window, this->bc_y, 0, crumbs_line, lr, role_t::VCR_STATUS);
this->bc_window, this->vc_y, 0, crumbs_line, lr, role_t::VCR_STATUS);
if (this->bc_selected_crumb) {
this->bc_match_view.set_x(sel_crumb_offset);
}
view_curses::do_update();
return true;
}
void
@ -172,6 +175,7 @@ breadcrumb_curses::reload_data()
void
breadcrumb_curses::focus()
{
this->bc_match_view.set_y(this->vc_y + 1);
this->bc_focused_crumbs = this->bc_line_source();
if (this->bc_focused_crumbs.empty()) {
return;

@ -42,14 +42,6 @@ class breadcrumb_curses : public view_curses {
public:
breadcrumb_curses();
void set_y(int y)
{
this->bc_y = y;
this->bc_match_view.set_y(y + 1);
}
int get_y() const { return this->bc_y; }
void set_window(WINDOW* win)
{
this->bc_window = win;
@ -66,7 +58,7 @@ public:
bool handle_key(int ch);
void do_update() override;
bool do_update() override;
void reload_data();
@ -90,7 +82,6 @@ private:
WINDOW* bc_window{nullptr};
std::function<std::vector<breadcrumb::crumb>()> bc_line_source;
int bc_y{0};
std::vector<breadcrumb::crumb> bc_focused_crumbs;
nonstd::optional<size_t> bc_selected_crumb;
nonstd::optional<size_t> bc_last_selected_crumb;

@ -44,7 +44,7 @@ using namespace lnav::roles::literals;
filter_sub_source::filter_sub_source(std::shared_ptr<readline_curses> editor)
: fss_editor(editor)
{
this->fss_editor->set_left(25);
this->fss_editor->set_x(25);
this->fss_editor->set_width(-1);
this->fss_editor->set_save_history(!(lnav_data.ld_flags & LNF_SECURE_MODE));
this->fss_regex_context.set_highlighter(readline_regex_highlighter)
@ -656,7 +656,7 @@ filter_sub_source::rl_display_matches(readline_curses* rc)
this->fss_match_view.set_window(this->tss_view->get_window());
this->fss_match_view.set_y(rc->get_y() + 1);
this->fss_match_view.set_x(rc->get_left() + rc->get_match_start());
this->fss_match_view.set_x(rc->get_x() + rc->get_match_start());
this->fss_match_view.set_width(width + 3);
this->fss_match_view.set_needs_update();
this->fss_match_view.reload_data();

@ -275,8 +275,7 @@ handle_paging_key(int ch)
} else {
lnav_data.ld_rl_view->set_value(
"error: mouse support is not available, make sure your "
"TERM is set to "
"xterm or xterm-256color");
"TERM is set to xterm or xterm-256color");
}
break;

@ -29,6 +29,7 @@
* @file listview_curses.cc
*/
#include <chrono>
#include <cmath>
#include "listview_curses.hh"
@ -40,10 +41,25 @@
#include "base/lnav_log.hh"
#include "config.h"
using namespace std::chrono_literals;
list_gutter_source listview_curses::DEFAULT_GUTTER_SOURCE;
listview_curses::listview_curses() : lv_scroll(noop_func{}) {}
bool
listview_curses::contains(int x, int y) const
{
auto dim = this->get_dimensions();
if (this->vc_x <= x && x < this->vc_x + dim.second && this->vc_y <= y
&& y < this->vc_y + dim.first)
{
return true;
}
return false;
}
void
listview_curses::update_top_from_selection()
{
@ -369,34 +385,36 @@ listview_curses::get_overlay_top(vis_line_t row, size_t count, size_t total)
return 0_vl;
}
void
bool
listview_curses::do_update()
{
bool retval = false;
if (this->lv_window == nullptr || this->lv_height == 0 || !this->vc_visible)
{
view_curses::do_update();
return;
return view_curses::do_update();
}
std::vector<attr_line_t> row_overlay_content;
vis_line_t height;
unsigned long width;
this->update_top_from_selection();
this->get_dimensions(height, width);
if (height <= 0) {
return retval;
}
this->update_top_from_selection();
while (this->vc_needs_update) {
auto& vc = view_colors::singleton();
vis_line_t row;
attr_line_t overlay_line;
struct line_range lr;
unsigned long wrap_width;
int y = this->lv_y, bottom;
int y = this->vc_y, bottom;
auto role_attrs = vc.attrs_for_role(this->vc_default_role);
if (height <= 0) {
return;
}
retval = true;
if (this->vc_width > 0) {
width = std::min((unsigned long) this->vc_width, width);
}
@ -413,14 +431,16 @@ listview_curses::do_update()
std::vector<attr_line_t> rows(
std::min((size_t) height, row_count - (int) this->lv_top));
this->lv_source->listview_value_for_rows(*this, row, rows);
this->lv_display_lines.clear();
while (y < bottom) {
lr.lr_start = this->lv_left;
lr.lr_end = this->lv_left + wrap_width;
if (this->lv_overlay_source != nullptr
&& this->lv_overlay_source->list_static_overlay(
*this, y - this->lv_y, bottom - this->lv_y, overlay_line))
*this, y - this->vc_y, bottom - this->vc_y, overlay_line))
{
mvwattrline(this->lv_window, y, this->lv_x, overlay_line, lr);
this->lv_display_lines.push_back(static_overlay_content{});
mvwattrline(this->lv_window, y, this->vc_x, overlay_line, lr);
overlay_line.clear();
++y;
} else if (row < (int) row_count) {
@ -430,14 +450,15 @@ listview_curses::do_update()
require_ge(attr.sa_range.lr_start, 0);
}
this->lv_display_lines.push_back(main_content{row});
view_curses::mvwattrline_result write_res;
do {
if (this->lv_word_wrap) {
mvwhline(this->lv_window, y, this->lv_x, ' ', width);
mvwhline(this->lv_window, y, this->vc_x, ' ', width);
}
write_res = mvwattrline(this->lv_window,
y,
this->lv_x,
this->vc_x,
al,
lr,
this->vc_default_role);
@ -469,9 +490,11 @@ listview_curses::do_update()
ov_hdr_attrs.ta_attrs |= A_UNDERLINE;
auto ov_hdr = hdr.value().with_attr_for_all(
VC_STYLE.value(ov_hdr_attrs));
this->lv_display_lines.push_back(
static_overlay_content{});
mvwattrline(this->lv_window,
y,
this->lv_x,
this->vc_x,
ov_hdr,
lr,
role_t::VCR_STATUS_INFO);
@ -488,9 +511,11 @@ listview_curses::do_update()
row_overlay_content[overlay_row].with_attr_for_all(
VC_ROLE.value(role_t::VCR_CURSOR_LINE));
}
this->lv_display_lines.push_back(
overlay_content{overlay_row});
mvwattrline(this->lv_window,
y,
this->lv_x,
this->vc_x,
row_overlay_content[overlay_row],
lr,
role_t::VCR_ALT_ROW);
@ -545,7 +570,7 @@ listview_curses::do_update()
nullptr);
mvwaddch(this->lv_window,
gutter_y,
this->lv_x + width - 2,
this->vc_x + width - 2,
ch);
}
}
@ -558,7 +583,8 @@ listview_curses::do_update()
vc.ensure_color_pair(role_attrs.ta_fg_color,
role_attrs.ta_bg_color),
nullptr);
mvwhline(this->lv_window, y, this->lv_x, ' ', width);
this->lv_display_lines.push_back(empty_space{});
mvwhline(this->lv_window, y, this->vc_x, ' ', width);
++y;
blank_rows += 1;
}
@ -577,19 +603,18 @@ listview_curses::do_update()
double progress = 1.0;
double coverage = 1.0;
double adjusted_height = (double) row_count / (double) height;
vis_line_t lines;
if (row_count > 0) {
progress = (double) this->lv_top / (double) row_count;
coverage = (double) height / (double) row_count;
}
y = this->lv_y + (int) (progress * (double) height);
lines = vis_line_t(
y + std::min((int) height, (int) (coverage * (double) height)));
this->lv_scroll_top = (int) (progress * (double) height);
this->lv_scroll_bottom = this->lv_scroll_top
+ std::min((int) height, (int) (coverage * (double) height));
for (unsigned int gutter_y = this->lv_y;
gutter_y < (this->lv_y + height);
for (unsigned int gutter_y = this->vc_y;
gutter_y < (this->vc_y + height);
gutter_y++)
{
int range_start = 0, range_end;
@ -600,14 +625,14 @@ listview_curses::do_update()
if (row_count > 0) {
range_start
= (double) (gutter_y - this->lv_y) * adjusted_height;
= (double) (gutter_y - this->vc_y) * adjusted_height;
}
range_end = range_start + adjusted_height;
this->lv_gutter_source->listview_gutter_value_for_range(
*this, range_start, range_end, ch, role, bar_role);
if (gutter_y >= (unsigned int) y
&& gutter_y <= (unsigned int) lines)
if (gutter_y >= this->vc_y + this->lv_scroll_top
&& gutter_y <= this->vc_y + this->lv_scroll_bottom)
{
role = bar_role;
}
@ -617,26 +642,26 @@ listview_curses::do_update()
attrs.ta_attrs,
vc.ensure_color_pair(attrs.ta_fg_color, attrs.ta_bg_color),
nullptr);
mvwaddch(this->lv_window, gutter_y, this->lv_x + width - 1, ch);
mvwaddch(this->lv_window, gutter_y, this->vc_x + width - 1, ch);
}
wmove(this->lv_window, this->lv_y + height - 1, this->lv_x);
wmove(this->lv_window, this->vc_y + height - 1, this->vc_x);
}
if (this->lv_show_bottom_border) {
cchar_t row_ch[width];
int y = this->lv_y + height - 1;
int y = this->vc_y + height - 1;
mvwin_wchnstr(this->lv_window, y, this->lv_x, row_ch, width - 1);
mvwin_wchnstr(this->lv_window, y, this->vc_x, row_ch, width - 1);
for (unsigned long lpc = 0; lpc < width - 1; lpc++) {
row_ch[lpc].attr |= A_UNDERLINE;
}
mvwadd_wchnstr(this->lv_window, y, this->lv_x, row_ch, width - 1);
mvwadd_wchnstr(this->lv_window, y, this->vc_x, row_ch, width - 1);
}
this->vc_needs_update = false;
}
view_curses::do_update();
return view_curses::do_update() || retval;
}
void
@ -766,6 +791,9 @@ scroll_polarity(mouse_button_t button)
bool
listview_curses::handle_mouse(mouse_event& me)
{
auto GUTTER_REPEAT_DELAY
= std::chrono::duration_cast<std::chrono::microseconds>(100ms).count();
vis_line_t inner_height, height;
struct timeval diff;
unsigned long width;
@ -776,30 +804,40 @@ listview_curses::handle_mouse(mouse_event& me)
switch (me.me_button) {
case mouse_button_t::BUTTON_SCROLL_UP:
case mouse_button_t::BUTTON_SCROLL_DOWN:
if (diff.tv_sec > 0 || diff.tv_usec > 80000) {
this->lv_scroll_accel = 1;
this->lv_scroll_velo = 0;
} else {
this->lv_scroll_accel += 2;
}
this->lv_scroll_velo += this->lv_scroll_accel;
this->shift_top(vis_line_t(scroll_polarity(me.me_button)
* this->lv_scroll_velo),
case mouse_button_t::BUTTON_SCROLL_DOWN: {
this->shift_top(vis_line_t(scroll_polarity(me.me_button) * 2_vl),
true);
break;
return true;
}
default:
break;
}
this->lv_mouse_time = me.me_time;
if (me.me_button != mouse_button_t::BUTTON_LEFT || inner_height == 0
|| (this->lv_mouse_mode != lv_mode_t::DRAG
&& me.me_x < (int) (width - 2)))
{
if (me.me_button != mouse_button_t::BUTTON_LEFT || inner_height == 0) {
return false;
}
switch (this->lv_mouse_mode) {
case lv_mode_t::NONE: {
if (me.me_x < (int) (width - 2)) {
return false;
}
break;
}
case lv_mode_t::DRAG:
break;
case lv_mode_t::UP:
case lv_mode_t::DOWN:
if (me.me_x < (int) (width - 2)) {
return true;
}
break;
}
if (me.me_state != mouse_button_state_t::BUTTON_STATE_RELEASED
&& this->lv_mouse_mode != lv_mode_t::DRAG && diff.tv_sec == 0
&& diff.tv_usec < GUTTER_REPEAT_DELAY)
{
return true;
}
this->lv_mouse_time = me.me_time;
if (me.me_state == mouse_button_state_t::BUTTON_STATE_RELEASED) {
this->lv_mouse_y = -1;
@ -807,19 +845,14 @@ listview_curses::handle_mouse(mouse_event& me)
return true;
}
int scroll_top, scroll_bottom, shift_amount = 0, new_top = 0;
double top_pct, bot_pct, pct;
top_pct = (double) this->get_top() / (double) inner_height;
bot_pct = (double) this->get_bottom() / (double) inner_height;
scroll_top = (this->get_y() + (int) (top_pct * (double) height));
scroll_bottom = (this->get_y() + (int) (bot_pct * (double) height));
int shift_amount = 0;
if (this->lv_mouse_mode == lv_mode_t::NONE) {
if ((scroll_top - 1) <= me.me_y && me.me_y <= (scroll_bottom + 1)) {
if (this->lv_scroll_top <= me.me_y && me.me_y <= this->lv_scroll_bottom)
{
this->lv_mouse_mode = lv_mode_t::DRAG;
this->lv_mouse_y = me.me_y - scroll_top;
} else if (me.me_y < scroll_top) {
this->lv_mouse_y = me.me_y - this->lv_scroll_top;
} else if (me.me_y < this->lv_scroll_top) {
this->lv_mouse_mode = lv_mode_t::UP;
} else {
this->lv_mouse_mode = lv_mode_t::DOWN;
@ -832,27 +865,28 @@ listview_curses::handle_mouse(mouse_event& me)
break;
case lv_mode_t::UP:
if (me.me_y < scroll_top) {
if (me.me_y < this->lv_scroll_top) {
shift_amount = -1 * height;
}
break;
case lv_mode_t::DOWN:
if (me.me_y > scroll_bottom) {
if (me.me_y > this->lv_scroll_bottom) {
shift_amount = height;
}
break;
case lv_mode_t::DRAG:
pct = (double) inner_height / (double) height;
new_top = me.me_y - this->get_y() - this->lv_mouse_y;
case lv_mode_t::DRAG: {
auto pct = (double) inner_height / (double) height;
auto new_top = me.me_y - this->lv_mouse_y;
new_top = (int) floor(((double) new_top * pct) + 0.5);
this->set_top(vis_line_t(new_top));
this->set_top(vis_line_t(new_top), true);
break;
}
}
if (shift_amount != 0) {
this->shift_top(vis_line_t(shift_amount));
this->shift_top(vis_line_t(shift_amount), true);
}
return true;

@ -307,26 +307,6 @@ public:
/** @return The curses window this view is attached to. */
WINDOW* get_window() const { return this->lv_window; }
void set_y(unsigned int y)
{
if (y != this->lv_y) {
this->lv_y = y;
this->set_needs_update();
}
}
unsigned int get_y() const { return this->lv_y; }
void set_x(unsigned int x)
{
if (x != this->lv_x) {
this->lv_x = x;
this->set_needs_update();
}
}
unsigned int get_x() const { return this->lv_x; }
/**
* Set the line number to be displayed at the top of the view. If the
* value is invalid, flash() will be called. If the value is valid, the
@ -478,7 +458,7 @@ public:
getmaxyx(this->lv_window, height, width_out);
if (this->lv_height < 0) {
height_out = vis_line_t(height) + this->lv_height
- vis_line_t(this->lv_y);
- vis_line_t(this->vc_y);
if (height_out < 0_vl) {
height_out = 0_vl;
}
@ -486,8 +466,8 @@ public:
height_out = this->lv_height;
}
}
if (this->lv_x < width_out) {
width_out -= this->lv_x;
if (this->vc_x < width_out) {
width_out -= this->vc_x;
} else {
width_out = 0;
}
@ -514,9 +494,11 @@ public:
/**
* Query the data source and draw the visible lines on the display.
*/
void do_update();
bool do_update() override;
bool handle_mouse(mouse_event& me);
bool handle_mouse(mouse_event& me) override;
bool contains(int x, int y) const override;
listview_curses& set_tail_space(vis_line_t space)
{
@ -527,14 +509,14 @@ public:
vis_line_t get_tail_space() const { return this->lv_tail_space; }
void log_state()
void log_state() override
{
log_debug("listview_curses=%p", this);
log_debug(
" lv_title=%s; lv_y=%u; lv_top=%d; lv_left=%d; lv_height=%d; "
" lv_title=%s; vc_y=%u; lv_top=%d; lv_left=%d; lv_height=%d; "
"lv_selection=%d; inner_height=%d",
this->lv_title.c_str(),
this->lv_y,
this->vc_y,
(int) this->lv_top,
(int) this->lv_left,
this->lv_height,
@ -572,8 +554,6 @@ protected:
list_overlay_source* lv_overlay_source{nullptr};
action lv_scroll; /*< The scroll action. */
WINDOW* lv_window{nullptr}; /*< The window that contains this view. */
unsigned int lv_x{0};
unsigned int lv_y{0}; /*< The y offset of this view. */
vis_line_t lv_top{0}; /*< The line at the top of the view. */
unsigned int lv_left{0}; /*< The column at the left of the view. */
vis_line_t lv_height{0}; /*< The abs/rel height of the view. */
@ -598,6 +578,24 @@ protected:
int lv_mouse_y{-1};
lv_mode_t lv_mouse_mode{lv_mode_t::NONE};
vis_line_t lv_tail_space{1};
struct main_content {
vis_line_t mc_line;
};
struct static_overlay_content {};
struct overlay_content {
vis_line_t oc_line;
};
struct empty_space {};
using display_line_content_t = mapbox::util::variant<main_content,
static_overlay_content,
overlay_content,
empty_space>;
std::vector<display_line_content_t> lv_display_lines;
unsigned int lv_scroll_top{0};
unsigned int lv_scroll_bottom{0};
};
#endif

@ -665,47 +665,6 @@ update_view_position(listview_curses* lv)
};
}
class lnav_behavior : public mouse_behavior {
public:
void mouse_event(int button, bool release, int x, int y) override
{
textview_curses* tc = *(lnav_data.ld_view_stack.top());
struct mouse_event me;
switch (button & xterm_mouse::XT_BUTTON__MASK) {
case xterm_mouse::XT_BUTTON1:
me.me_button = mouse_button_t::BUTTON_LEFT;
break;
case xterm_mouse::XT_BUTTON2:
me.me_button = mouse_button_t::BUTTON_MIDDLE;
break;
case xterm_mouse::XT_BUTTON3:
me.me_button = mouse_button_t::BUTTON_RIGHT;
break;
case xterm_mouse::XT_SCROLL_UP:
me.me_button = mouse_button_t::BUTTON_SCROLL_UP;
break;
case xterm_mouse::XT_SCROLL_DOWN:
me.me_button = mouse_button_t::BUTTON_SCROLL_DOWN;
break;
}
if (button & xterm_mouse::XT_DRAG_FLAG) {
me.me_state = mouse_button_state_t::BUTTON_STATE_DRAGGED;
} else if (release) {
me.me_state = mouse_button_state_t::BUTTON_STATE_RELEASED;
} else {
me.me_state = mouse_button_state_t::BUTTON_STATE_PRESSED;
}
gettimeofday(&me.me_time, nullptr);
me.me_x = x - 1;
me.me_y = y - tc->get_y() - 1;
tc->handle_mouse(me);
}
};
static bool
handle_config_ui_key(int ch)
{
@ -1373,11 +1332,11 @@ looper()
auto top_source = injector::get<std::shared_ptr<top_status_source>>();
lnav_data.ld_status[LNS_TOP].set_top(0);
lnav_data.ld_status[LNS_TOP].set_y(0);
lnav_data.ld_status[LNS_TOP].set_default_role(
role_t::VCR_INACTIVE_STATUS);
lnav_data.ld_status[LNS_TOP].set_data_source(top_source.get());
lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc->get_height() + 1));
lnav_data.ld_status[LNS_BOTTOM].set_y(-(rlc->get_height() + 1));
for (auto& stat_bar : lnav_data.ld_status) {
stat_bar.set_window(lnav_data.ld_window);
}
@ -1596,7 +1555,9 @@ looper()
{
lnav_data.ld_view_stack.set_needs_update();
}
lnav_data.ld_view_stack.do_update();
if (lnav_data.ld_view_stack.do_update()) {
breadcrumb_view.set_needs_update();
}
lnav_data.ld_doc_view.do_update();
lnav_data.ld_example_view.do_update();
lnav_data.ld_match_view.do_update();
@ -1685,6 +1646,11 @@ looper()
gettimeofday(&current_time, nullptr);
lnav_data.ld_input_dispatcher.poll(current_time);
if (lb.lb_last_view != nullptr) {
lb.lb_last_event.me_time = current_time;
lb.lb_last_view->handle_mouse(lb.lb_last_event);
}
if (rc < 0) {
switch (errno) {
case 0:

@ -821,7 +821,7 @@ readline_curses::start()
if (this->vc_width > 0) {
ws.ws_col = this->vc_width;
} else if (this->vc_width < 0) {
ws.ws_col -= this->vc_left;
ws.ws_col -= this->vc_x;
ws.ws_col += this->vc_width;
}
@ -1294,11 +1294,11 @@ readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds)
rc = read(this->rc_pty[RCF_MASTER], buffer, sizeof(buffer));
if (rc > 0) {
int old_x = this->vc_x;
int old_x = this->vc_cursor_x;
this->rc_suggestion.clear();
this->map_output(buffer, rc);
if (this->vc_x != old_x) {
if (this->vc_cursor_x != old_x) {
this->rc_change(this);
}
}
@ -1451,7 +1451,7 @@ readline_curses::focus(int context,
al.append(lnav::roles::suggestion(this->rc_suggestion));
view_curses::mvwattrline(this->vc_window,
this->get_actual_y(),
this->vc_left,
this->vc_x,
al,
line_range{0, (int) this->get_actual_width()});
if (!initial.empty()) {
@ -1495,7 +1495,7 @@ readline_curses::abort()
{
char buffer[1024];
this->vc_x = 0;
this->vc_cursor_x = 0;
snprintf(buffer, sizeof(buffer), "a");
if (sendstring(this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer))
== -1)
@ -1600,11 +1600,11 @@ readline_curses::clear_possibilities(int context, std::string type)
}
}
void
bool
readline_curses::do_update()
{
if (!this->vc_visible || this->vc_window == nullptr) {
return;
return false;
}
auto actual_width = this->get_actual_width();
@ -1614,7 +1614,7 @@ readline_curses::do_update()
attr_line_t alt_al;
auto& vc = view_colors::singleton();
wmove(this->vc_window, this->get_actual_y(), this->vc_left);
wmove(this->vc_window, this->get_actual_y(), this->vc_x);
auto attrs = vc.attrs_for_role(role_t::VCR_TEXT);
wattr_set(this->vc_window,
attrs.ta_attrs,
@ -1642,7 +1642,7 @@ readline_curses::do_update()
lr.lr_end = this->rc_value.length();
view_curses::mvwattrline(this->vc_window,
this->get_actual_y(),
this->vc_left,
this->vc_x,
this->rc_value,
lr);
this->set_x(0);
@ -1654,24 +1654,27 @@ readline_curses::do_update()
auto al = this->vc_line;
if (hl != nullptr) {
hl(al, this->vc_left + this->vc_x);
hl(al, this->vc_x + this->vc_cursor_x);
}
al.append(lnav::roles::suggestion(this->rc_suggestion));
view_curses::mvwattrline(this->vc_window,
this->get_actual_y(),
this->vc_left,
this->vc_x,
al,
line_range{0, (int) actual_width});
wmove(
this->vc_window, this->get_actual_y(), this->vc_left + this->vc_x);
wmove(this->vc_window,
this->get_actual_y(),
this->vc_x + this->vc_cursor_x);
}
return true;
}
std::string
readline_curses::get_match_string() const
{
auto len = std::min((size_t) this->vc_x, this->rc_line_buffer.size())
auto len = std::min((size_t) this->vc_cursor_x, this->rc_line_buffer.size())
- this->rc_match_start;
auto* context = this->get_active_context();
@ -1734,7 +1737,7 @@ readline_curses::window_change()
if (this->vc_width > 0) {
ws.ws_col = this->vc_width;
} else if (this->vc_width < 0) {
ws.ws_col -= this->vc_left;
ws.ws_col -= this->vc_x;
ws.ws_col += this->vc_width;
}
if (ioctl(this->rc_pty[RCF_MASTER], TIOCSWINSZ, &ws) == -1) {

@ -186,7 +186,7 @@ public:
void start();
void do_update() override;
bool do_update() override;
void window_change();

@ -84,7 +84,7 @@ status_field::set_stitch_value(role_t left, role_t right)
sa.emplace_back(lr, VC_ROLE.value(right));
}
void
bool
statusview_curses::do_update()
{
int top, field, field_count, left = 0, right;
@ -92,13 +92,13 @@ statusview_curses::do_update()
unsigned long width, height;
if (!this->vc_visible || this->sc_window == nullptr) {
return;
return false;
}
getmaxyx(this->sc_window, height, width);
this->window_change();
top = this->sc_top < 0 ? height + this->sc_top : this->sc_top;
top = this->vc_y < 0 ? height + this->vc_y : this->vc_y;
right = width;
auto attrs = vc.attrs_for_role(
this->sc_enabled ? this->sc_default_role : role_t::VCR_INACTIVE_STATUS);
@ -181,6 +181,8 @@ statusview_curses::do_update()
}
}
wmove(this->sc_window, top + 1, 0);
return true;
}
void

@ -162,9 +162,6 @@ public:
void set_data_source(status_data_source* src) { this->sc_source = src; }
status_data_source* get_data_source() { return this->sc_source; }
void set_top(int top) { this->sc_top = top; }
int get_top() const { return this->sc_top; }
void set_window(WINDOW* win) { this->sc_window = win; }
WINDOW* get_window() { return this->sc_window; }
@ -176,12 +173,11 @@ public:
void window_change();
void do_update() override;
bool do_update() override;
private:
status_data_source* sc_source{nullptr};
WINDOW* sc_window{nullptr};
int sc_top{0};
bool sc_enabled{true};
role_t sc_default_role{role_t::VCR_STATUS};
};

@ -396,8 +396,7 @@ textview_curses::handle_mouse(mouse_event& me)
unsigned long width;
vis_line_t height;
if (this->tc_selection_start == -1_vl && listview_curses::handle_mouse(me))
{
if (!this->tc_selection_start && listview_curses::handle_mouse(me)) {
return true;
}
@ -411,64 +410,58 @@ textview_curses::handle_mouse(mouse_event& me)
return false;
}
vis_line_t mouse_line(this->get_top() + me.me_y);
if (mouse_line > this->get_bottom()) {
mouse_line = this->get_bottom();
}
auto mouse_line = this->lv_display_lines[me.me_y];
this->get_dimensions(height, width);
switch (me.me_state) {
case mouse_button_state_t::BUTTON_STATE_PRESSED:
this->tc_selection_start = mouse_line;
this->tc_selection_last = -1_vl;
this->tc_selection_cleared = false;
case mouse_button_state_t::BUTTON_STATE_PRESSED: {
if (!this->lv_selectable) {
this->set_selectable(true);
}
mouse_line.match(
[this, &me](const main_content& mc) {
if (me.is_modifier_pressed(mouse_event::modifier_t::shift))
{
this->tc_selection_start = mc.mc_line;
}
this->set_selection(mc.mc_line);
this->tc_press_event = me;
},
[](const static_overlay_content& soc) {
},
[](const overlay_content& oc) {
},
[](const empty_space& es) {});
break;
case mouse_button_state_t::BUTTON_STATE_DRAGGED:
}
case mouse_button_state_t::BUTTON_STATE_DRAGGED: {
if (me.me_y <= 0) {
this->shift_top(-1_vl);
this->shift_selection(listview_curses::shift_amount_t::up_line);
me.me_y = 0;
mouse_line = this->get_top();
}
if (me.me_y >= height
&& this->get_top() < this->get_top_for_last_row())
mouse_line = main_content{this->get_top()};
} else if (me.me_y >= height
&& this->get_top() < this->get_top_for_last_row())
{
this->shift_top(1_vl);
this->shift_selection(
listview_curses::shift_amount_t::down_line);
me.me_y = height;
mouse_line = this->get_bottom();
}
if (this->tc_selection_last == mouse_line)
break;
if (this->tc_selection_last != -1) {
this->toggle_user_mark(&textview_curses::BM_USER,
this->tc_selection_start,
this->tc_selection_last);
}
if (this->tc_selection_start == mouse_line) {
this->tc_selection_last = -1_vl;
} else {
if (!this->tc_selection_cleared) {
if (this->tc_sub_source != nullptr) {
this->tc_sub_source->text_clear_marks(&BM_USER);
}
this->tc_bookmarks[&BM_USER].clear();
this->tc_selection_cleared = true;
}
this->toggle_user_mark(
&BM_USER, this->tc_selection_start, mouse_line);
this->tc_selection_last = mouse_line;
} else if (mouse_line.is<main_content>()) {
this->set_selection(mouse_line.get<main_content>().mc_line);
}
this->reload_data();
break;
case mouse_button_state_t::BUTTON_STATE_RELEASED:
this->tc_selection_start = -1_vl;
this->tc_selection_last = -1_vl;
this->tc_selection_cleared = false;
}
case mouse_button_state_t::BUTTON_STATE_RELEASED: {
if (this->tc_selection_start) {
this->toggle_user_mark(&BM_USER,
this->tc_selection_start.value(),
this->get_selection());
this->reload_data();
}
this->tc_selection_start = nonstd::nullopt;
break;
}
}
return true;
@ -509,15 +502,28 @@ textview_curses::textview_value_for_row(vis_line_t row, attr_line_t& value_out)
format_name = format_attr_opt.value().get();
}
if (this->is_selectable() && row == this->get_selection()
&& this->tc_cursor_role && this->tc_disabled_cursor_role)
if (this->is_selectable() && this->tc_cursor_role
&& this->tc_disabled_cursor_role)
{
auto role = this->get_overlay_selection()
? this->tc_disabled_cursor_role.value()
: this->tc_cursor_role.value();
vis_line_t sel_start, sel_end;
sa.emplace_back(line_range{orig_line.lr_start, -1},
VC_ROLE.value(role));
sel_start = sel_end = this->get_selection();
if (this->tc_selection_start) {
if (this->tc_selection_start.value() < sel_end) {
sel_start = this->tc_selection_start.value();
} else {
sel_end = this->tc_selection_start.value();
}
}
if (sel_start <= row && row <= sel_end) {
auto role = this->get_overlay_selection()
? this->tc_disabled_cursor_role.value()
: this->tc_cursor_role.value();
sa.emplace_back(line_range{orig_line.lr_start, -1},
VC_ROLE.value(role));
}
}
for (auto& tc_highlight : this->tc_highlights) {

@ -551,8 +551,6 @@ class text_delegate {
public:
virtual ~text_delegate() = default;
virtual void text_overlay(textview_curses& tc) {}
virtual bool text_handle_mouse(textview_curses& tc, mouse_event& me)
{
return false;
@ -726,14 +724,6 @@ public:
void reload_data();
void do_update()
{
this->listview_curses::do_update();
if (this->tc_delegate != nullptr) {
this->tc_delegate->text_overlay(*this);
}
}
bool toggle_hide_fields()
{
bool retval = this->tc_hide_fields;
@ -857,9 +847,8 @@ protected:
highlight_map_t tc_highlights;
std::set<highlight_source_t> tc_disabled_highlights;
vis_line_t tc_selection_start{-1_vl};
vis_line_t tc_selection_last{-1_vl};
bool tc_selection_cleared{false};
nonstd::optional<vis_line_t> tc_selection_start;
mouse_event tc_press_event;
bool tc_hide_fields{true};
bool tc_paused{false};

@ -129,6 +129,15 @@ struct utf_to_display_adjustment {
}
};
bool
view_curses::contains(int x, int y) const
{
if (this->vc_x <= x && x < this->vc_x + this->vc_width && this->vc_y == y) {
return true;
}
return false;
}
void
view_curses::awaiting_user_input()
{

@ -320,14 +320,28 @@ struct mouse_event {
mouse_event(mouse_button_t button = mouse_button_t::BUTTON_LEFT,
mouse_button_state_t state
= mouse_button_state_t::BUTTON_STATE_PRESSED,
uint8_t mods = 0,
int x = -1,
int y = -1)
: me_button(button), me_state(state), me_x(x), me_y(y)
: me_button(button), me_state(state), me_modifiers(mods), me_x(x),
me_y(y)
{
}
enum class modifier_t : uint8_t {
shift = 4,
meta = 8,
ctrl = 16,
};
bool is_modifier_pressed(modifier_t mod) const
{
return this->me_modifiers & lnav::enums::to_underlying(mod);
}
mouse_button_t me_button;
mouse_button_state_t me_state;
uint8_t me_modifiers;
struct timeval me_time {};
int me_x;
int me_y;
@ -343,21 +357,26 @@ public:
/**
* Update the curses display.
*/
virtual void do_update()
virtual bool do_update()
{
bool retval = false;
this->vc_needs_update = false;
if (!this->vc_visible) {
return;
return retval;
}
for (auto* child : this->vc_children) {
child->do_update();
retval = child->do_update() || retval;
}
return retval;
}
virtual bool handle_mouse(mouse_event& me) { return false; }
virtual bool contains(int x, int y) const;
void set_needs_update()
{
this->vc_needs_update = true;
@ -381,6 +400,33 @@ public:
bool is_visible() const { return this->vc_visible; }
/**
* Set the Y position of this view on the display. A value greater than
* zero is considered to be an absolute size. A value less than zero makes
* the position relative to the bottom of the enclosing window.
*
* @param y The Y position of the cursor on the curses display.
*/
void set_y(int y)
{
if (y != this->vc_y) {
this->vc_y = y;
this->set_needs_update();
}
}
int get_y() const { return this->vc_y; }
void set_x(unsigned int x)
{
if (x != this->vc_x) {
this->vc_x = x;
this->set_needs_update();
}
}
unsigned int get_x() const { return this->vc_x; }
void set_width(long width) { this->vc_width = width; }
long get_width() const { return this->vc_width; }
@ -403,6 +449,8 @@ protected:
bool vc_visible{true};
/** Flag to indicate if a display update is needed. */
bool vc_needs_update{true};
unsigned int vc_x{0};
int vc_y{0};
long vc_width{0};
std::vector<view_curses*> vc_children;
role_t vc_default_role{role_t::VCR_TEXT};
@ -421,22 +469,24 @@ public:
return this->vs_views.back();
}
void do_update() override
bool do_update() override
{
if (!this->vc_visible) {
return;
return false;
}
this->top() | [this](T* vc) {
bool retval;
this->top() | [this, &retval](T* vc) {
if (this->vc_needs_update) {
vc->set_needs_update();
}
vc->do_update();
retval = vc->do_update();
};
view_curses::do_update();
retval = view_curses::do_update() || retval;
this->vc_needs_update = false;
return retval;
}
void push_back(T* view)

@ -718,7 +718,7 @@ layout_views()
lnav_data.ld_user_message_view.set_visible(vis);
bottom -= 1;
lnav_data.ld_status[LNS_BOTTOM].set_top(bottom);
lnav_data.ld_status[LNS_BOTTOM].set_y(bottom);
lnav_data.ld_status[LNS_BOTTOM].set_enabled(!filters_open
&& !breadcrumb_open);
@ -727,7 +727,7 @@ layout_views()
lnav_data.ld_preview_view[1].set_y(bottom + 1);
lnav_data.ld_preview_view[1].set_visible(vis);
lnav_data.ld_status[LNS_PREVIEW1].set_top(bottom);
lnav_data.ld_status[LNS_PREVIEW1].set_y(bottom);
lnav_data.ld_status[LNS_PREVIEW1].set_visible(vis);
vis = preview_open0 && bottom.try_consume(preview_height0 + 1);
@ -735,7 +735,7 @@ layout_views()
lnav_data.ld_preview_view[0].set_y(bottom + 1);
lnav_data.ld_preview_view[0].set_visible(vis);
lnav_data.ld_status[LNS_PREVIEW0].set_top(bottom);
lnav_data.ld_status[LNS_PREVIEW0].set_y(bottom);
lnav_data.ld_status[LNS_PREVIEW0].set_visible(vis);
if (doc_side_by_side && doc_height > 0) {
@ -770,7 +770,7 @@ layout_views()
auto has_doc = lnav_data.ld_example_view.get_height() > 0_vl
|| lnav_data.ld_doc_view.get_height() > 0_vl;
lnav_data.ld_status[LNS_DOC].set_top(bottom);
lnav_data.ld_status[LNS_DOC].set_y(bottom);
lnav_data.ld_status[LNS_DOC].set_visible(has_doc && vis);
if (is_gantt) {
@ -783,7 +783,7 @@ layout_views()
lnav_data.ld_gantt_details_view.set_width(width);
lnav_data.ld_gantt_details_view.set_visible(vis);
lnav_data.ld_status[LNS_GANTT].set_top(bottom);
lnav_data.ld_status[LNS_GANTT].set_y(bottom);
lnav_data.ld_status[LNS_GANTT].set_visible(vis);
vis = bottom.try_consume(filter_height + (filters_open ? 1 : 0)
@ -799,11 +799,11 @@ layout_views()
lnav_data.ld_files_view.set_visible(filters_open && vis);
lnav_data.ld_status[LNS_FILTER_HELP].set_visible(filters_open && vis);
lnav_data.ld_status[LNS_FILTER_HELP].set_top(bottom + 1);
lnav_data.ld_status[LNS_FILTER_HELP].set_y(bottom + 1);
lnav_data.ld_status[LNS_FILTER].set_visible(vis);
lnav_data.ld_status[LNS_FILTER].set_enabled(filters_open);
lnav_data.ld_status[LNS_FILTER].set_top(bottom);
lnav_data.ld_status[LNS_FILTER].set_y(bottom);
vis = is_spectro && bottom.try_consume(5 + 1);
lnav_data.ld_spectro_details_view.set_y(bottom + 1);
@ -811,7 +811,7 @@ layout_views()
lnav_data.ld_spectro_details_view.set_width(width);
lnav_data.ld_spectro_details_view.set_visible(vis);
lnav_data.ld_status[LNS_SPECTRO].set_top(bottom);
lnav_data.ld_status[LNS_SPECTRO].set_y(bottom);
lnav_data.ld_status[LNS_SPECTRO].set_visible(vis);
lnav_data.ld_status[LNS_SPECTRO].set_enabled(lnav_data.ld_mode
== ln_mode_t::SPECTRO_DETAILS);
@ -1401,3 +1401,73 @@ clear_preview()
lnav_data.ld_preview_view[lpc].set_overlay_source(nullptr);
}
}
void
lnav_behavior::mouse_event(int button, bool release, int x, int y)
{
struct mouse_event me;
switch (button & xterm_mouse::XT_BUTTON__MASK) {
case xterm_mouse::XT_BUTTON1:
me.me_button = mouse_button_t::BUTTON_LEFT;
break;
case xterm_mouse::XT_BUTTON2:
me.me_button = mouse_button_t::BUTTON_MIDDLE;
break;
case xterm_mouse::XT_BUTTON3:
me.me_button = mouse_button_t::BUTTON_RIGHT;
break;
case xterm_mouse::XT_SCROLL_UP:
me.me_button = mouse_button_t::BUTTON_SCROLL_UP;
break;
case xterm_mouse::XT_SCROLL_DOWN:
me.me_button = mouse_button_t::BUTTON_SCROLL_DOWN;
break;
}
me.me_modifiers = button & xterm_mouse::XT_MODIFIER_MASK;
if (button & xterm_mouse::XT_DRAG_FLAG) {
me.me_state = mouse_button_state_t::BUTTON_STATE_DRAGGED;
} else if (release) {
me.me_state = mouse_button_state_t::BUTTON_STATE_RELEASED;
} else {
me.me_state = mouse_button_state_t::BUTTON_STATE_PRESSED;
}
auto width = getmaxx(lnav_data.ld_window);
gettimeofday(&me.me_time, nullptr);
me.me_x = x - 1;
if (me.me_x >= width) {
me.me_x = width - 1;
}
me.me_y = y - 1;
switch (me.me_state) {
case mouse_button_state_t::BUTTON_STATE_PRESSED: {
auto* tc = *(lnav_data.ld_view_stack.top());
if (tc->contains(me.me_x, me.me_y)) {
this->lb_last_view = tc;
}
break;
}
case mouse_button_state_t::BUTTON_STATE_DRAGGED:
case mouse_button_state_t::BUTTON_STATE_RELEASED: {
break;
}
}
if (this->lb_last_view != nullptr) {
me.me_y -= this->lb_last_view->get_y();
me.me_x -= this->lb_last_view->get_x();
this->lb_last_view->handle_mouse(me);
}
this->lb_last_event = me;
if (me.me_state == mouse_button_state_t::BUTTON_STATE_RELEASED
|| me.me_button == mouse_button_t::BUTTON_SCROLL_UP
|| me.me_button == mouse_button_t::BUTTON_SCROLL_DOWN)
{
this->lb_last_view = nullptr;
}
}

@ -34,8 +34,10 @@
#include "bookmarks.hh"
#include "help_text.hh"
#include "listview_curses.hh"
#include "logfile_fwd.hh"
#include "vis_line.hh"
#include "xterm_mouse.hh"
class textview_curses;
class hist_source2;
@ -100,4 +102,12 @@ bool moveto_cluster(nonstd::optional<vis_line_t> (
vis_line_t search_forward_from(textview_curses* tc);
textview_curses* get_textview_for_mode(ln_mode_t mode);
class lnav_behavior : public mouse_behavior {
public:
void mouse_event(int button, bool release, int x, int y) override;
view_curses* lb_last_view{nullptr};
struct mouse_event lb_last_event;
};
#endif

@ -17,7 +17,7 @@
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHAN`TABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@ -208,8 +208,8 @@ vt52_curses::map_output(const char* output, int len)
if (this->vc_expected_escape_len != -1) {
if (this->vc_escape_len == this->vc_expected_escape_len) {
auto& line_string = this->vc_line.get_string();
auto x_byte_index
= utf8_char_to_byte_index(line_string, this->vc_x);
auto x_byte_index = utf8_char_to_byte_index(
line_string, this->vc_cursor_x);
for (int esc_index = 0; esc_index < this->vc_escape_len;
esc_index++)
@ -222,7 +222,7 @@ vt52_curses::map_output(const char* output, int len)
}
x_byte_index += 1;
}
this->vc_x += 1;
this->vc_cursor_x += 1;
this->vc_escape_len = 0;
}
} else if ((cap = vt52_escape_map::singleton()[this->vc_escape])
@ -230,11 +230,11 @@ vt52_curses::map_output(const char* output, int len)
{
this->vc_escape_len = 0;
if (strcmp(cap, "ce") == 0) {
this->vc_line.erase_utf8_chars(this->vc_x);
this->vc_line.erase_utf8_chars(this->vc_cursor_x);
} else if (strcmp(cap, "kl") == 0) {
this->vc_x -= 1;
this->vc_cursor_x -= 1;
} else if (strcmp(cap, "kr") == 0) {
this->vc_x += 1;
this->vc_cursor_x += 1;
} else if (strcmp(cap, "BE") == 0 || strcmp(cap, "BD") == 0) {
// TODO pass bracketed paste mode through
} else {
@ -256,7 +256,7 @@ vt52_curses::map_output(const char* output, int len)
switch (next_ch) {
case STX:
this->vc_x = 0;
this->vc_cursor_x = 0;
this->vc_line.clear();
break;
@ -265,7 +265,7 @@ vt52_curses::map_output(const char* output, int len)
break;
case BACKSPACE:
this->vc_x -= 1;
this->vc_cursor_x -= 1;
break;
case ESCAPE:
@ -275,25 +275,25 @@ vt52_curses::map_output(const char* output, int len)
break;
case '\n':
this->vc_x = 0;
this->vc_cursor_x = 0;
this->vc_line.clear();
break;
case '\r':
this->vc_x = 0;
this->vc_cursor_x = 0;
break;
default: {
auto& line_string = this->vc_line.get_string();
auto x_byte_index
= utf8_char_to_byte_index(line_string, this->vc_x);
auto x_byte_index = utf8_char_to_byte_index(
line_string, this->vc_cursor_x);
if (x_byte_index < this->vc_line.length()) {
line_string[x_byte_index] = next_ch;
} else {
this->vc_line.append(1, next_ch);
}
this->vc_x += 1;
this->vc_cursor_x += 1;
break;
}
}
@ -301,14 +301,16 @@ vt52_curses::map_output(const char* output, int len)
}
}
void
bool
vt52_curses::do_update()
{
auto actual_width = this->get_actual_width();
view_curses::mvwattrline(this->vc_window,
this->get_actual_y(),
this->vc_left,
this->vc_x,
this->vc_line,
line_range{0, (int) actual_width});
wmove(this->vc_window, this->get_actual_y(), this->vc_left + this->vc_x);
wmove(
this->vc_window, this->get_actual_y(), this->vc_x + this->vc_cursor_x);
return true;
}

@ -59,27 +59,11 @@ public:
/** @return The curses window this view is attached to. */
WINDOW* get_window() { return this->vc_window; }
void set_left(int left) { this->vc_left = left; }
int get_left() const { return this->vc_left; }
/**
* Set the Y position of this view on the display. A value greater than
* zero is considered to be an absolute size. A value less than zero makes
* the position relative to the bottom of the enclosing window.
*
* @param y The Y position of the cursor on the curses display.
*/
void set_y(int y) { this->vc_y = y; }
/** @return The abs/rel Y position of the cursor on the curses display. */
int get_y() const { return this->vc_y; }
/** @param x The X position of the cursor on the curses display. */
void set_x(int x) { this->vc_x = x; }
void set_cursor_x(int x) { this->vc_cursor_x = x; }
/** @return The X position of the cursor on the curses display. */
int get_x() const { return this->vc_x; }
int get_cursor_x() const { return this->vc_cursor_x; }
/**
* @return The height of this view, which consists of a single line for
@ -112,7 +96,7 @@ public:
/**
* Paints any past lines and moves the cursor to the current X position.
*/
void do_update();
bool do_update() override;
const static char ESCAPE = 27; /*< VT52 Escape key value. */
const static char BACKSPACE = 8; /*< VT52 Backspace key value. */
@ -141,20 +125,18 @@ protected:
auto retval = getmaxx(this->vc_window);
if (this->vc_width < 0) {
retval -= this->vc_left;
retval -= this->vc_x;
retval += this->vc_width;
} else if (this->vc_width > 0) {
retval = this->vc_width;
} else {
retval = retval - this->vc_left;
retval = retval - this->vc_x;
}
return retval;
}
WINDOW* vc_window{nullptr}; /*< The window that contains this view. */
int vc_left{0};
int vc_x{0}; /*< The X position of the cursor. */
int vc_y{0}; /*< The Y position of the cursor. */
int vc_cursor_x{0}; /*< The X position of the cursor. */
int vc_max_height{0};
char vc_escape[16]; /*< Storage for escape sequences. */
int vc_escape_len{0}; /*< The number of chars in vc_escape. */

@ -84,6 +84,12 @@ public:
static const int XT_BUTTON__MASK
= XT_SCROLL_WHEEL_FLAG | XT_BUTTON1 | XT_BUTTON2 | XT_BUTTON3;
static const int XT_MODIFIER_SHIFT = 4;
static const int XT_MODIFIER_META = 8;
static const int XT_MODIFIER_CTRL = 16;
static const int XT_MODIFIER_MASK
= XT_MODIFIER_SHIFT | XT_MODIFIER_META | XT_MODIFIER_CTRL;
static const char* XT_TERMCAP;
static const char* XT_TERMCAP_TRACKING;
static const char* XT_TERMCAP_SGR;

@ -38,7 +38,7 @@ class test_colors : public view_curses {
public:
test_colors() : tc_window(nullptr) {}
void do_update() override
bool do_update() override
{
auto& vc = view_colors::singleton();
int lpc;
@ -68,7 +68,9 @@ public:
al.with_attr(
{line_range{8, 11}, VC_STYLE.value(text_attrs{A_REVERSE})});
test_colors::mvwattrline(this->tc_window, lpc, 0, al, lr);
};
return true;
}
WINDOW* tc_window;
};

Loading…
Cancel
Save