1 /***************************************************************************
2 * Copyright (C) 2008-2017 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
26 #include <sys/select.h>
29 #include "utility/readline.h"
30 #include "utility/string.h"
31 #include "utility/wide_string.h"
55 if (w
->runPromptHook(rl_line_buffer
, &done
))
57 // Do not end if readline is in one of its commands, e.g. searching
58 // through history, as it doesn't actually make readline exit and it
59 // becomes stuck in a loop.
60 if (!RL_ISSTATE(RL_STATE_DISPATCHING
) && done
)
65 w
->goToXY(x
, start_y
);
68 result
= w
->readKey();
69 if (!w
->FDCallbacksListEmpty())
71 w
->goToXY(x
, start_y
);
75 while (result
== ERR
);
81 auto print_char
= [](wchar_t wc
) {
87 auto print_string
= [](wchar_t *ws
, size_t len
) {
89 for (size_t i
= 0; i
< len
; ++i
)
94 auto narrow_to_wide
= [](wchar_t *dest
, const char *src
, size_t n
) {
96 // convert the string and substitute invalid multibyte chars with dots.
97 for (size_t i
= 0; i
< n
;)
99 int ret
= mbtowc(&dest
[result
], &src
[i
], n
-i
);
112 throw std::runtime_error("mbtowc: unexpected return value");
117 // copy the part of the string that is before the cursor to pre_pos
118 char pt
= rl_line_buffer
[rl_point
];
119 rl_line_buffer
[rl_point
] = 0;
120 wchar_t pre_pos
[rl_point
+1];
121 pre_pos
[narrow_to_wide(pre_pos
, rl_line_buffer
, rl_point
)] = 0;
122 rl_line_buffer
[rl_point
] = pt
;
124 int pos
= wcswidth(pre_pos
, rl_point
);
128 // clear the area for the string
129 mvwhline(w
->raw(), start_y
, start_x
, ' ', width
+1);
131 w
->goToXY(start_x
, start_y
);
132 if (size_t(pos
) <= width
)
134 // if the current position in the string is not bigger than allowed
135 // width, print the part of the string before cursor position...
137 print_string(pre_pos
, pos
);
139 // ...and then print the rest char-by-char until there is no more area
140 wchar_t post_pos
[rl_end
-rl_point
+1];
141 post_pos
[narrow_to_wide(post_pos
, rl_line_buffer
+rl_point
, rl_end
-rl_point
)] = 0;
144 for (wchar_t *c
= post_pos
; *c
!= 0; ++c
)
163 // if the current position in the string is bigger than allowed
164 // width, we always keep the cursor at the end of the line (it
165 // would be nice to have more flexible scrolling, but for now
166 // let's stick to that) by cutting the beginning of the part
167 // of the string before the cursor until it fits the area.
169 wchar_t *mod_pre_pos
= pre_pos
;
170 while (*mod_pre_pos
!= 0)
173 int n
= wcwidth(*mod_pre_pos
);
178 if (size_t(pos
) <= width
)
181 print_string(mod_pre_pos
, pos
);
183 w
->goToXY(start_x
+pos
, start_y
);
188 rl_insert_text(base
);
194 int color_pair_counter
;
195 std::vector
<int> color_pair_map
;
201 const short Color::transparent
= -1;
202 const short Color::current
= -2;
204 Color
Color::Default(0, 0, true, false);
205 Color
Color::Black(COLOR_BLACK
, Color::current
);
206 Color
Color::Red(COLOR_RED
, Color::current
);
207 Color
Color::Green(COLOR_GREEN
, Color::current
);
208 Color
Color::Yellow(COLOR_YELLOW
, Color::current
);
209 Color
Color::Blue(COLOR_BLUE
, Color::current
);
210 Color
Color::Magenta(COLOR_MAGENTA
, Color::current
);
211 Color
Color::Cyan(COLOR_CYAN
, Color::current
);
212 Color
Color::White(COLOR_WHITE
, Color::current
);
213 Color
Color::End(0, 0, false, true);
215 int Color::pairNumber() const
217 // If colors are disabled, return default pair value.
218 if (color_pair_map
.empty())
223 throw std::logic_error("'end' doesn't have a corresponding pair number");
224 else if (!isDefault())
226 if (!currentBackground())
227 result
= (background() + 1) % COLORS
;
229 result
+= foreground() % COLORS
;
231 assert(result
< int(color_pair_map
.size()));
233 // NCurses allows for a limited number of color pairs to be registered, so
234 // in order to be able to support all the combinations we want to, we need
235 // to dynamically register only pairs of colors we're actually using.
236 if (!color_pair_map
[result
])
238 // Check if there are any unused pairs left and either register the one
239 // that was requested or return a default one if there is no space left.
240 if (color_pair_counter
>= COLOR_PAIRS
)
244 init_pair(color_pair_counter
, foreground(), background());
245 color_pair_map
[result
] = color_pair_counter
;
246 ++color_pair_counter
;
249 result
= color_pair_map
[result
];
254 std::istream
&operator>>(std::istream
&is
, Color
&c
)
256 const short invalid_color_value
= -1337;
257 auto get_single_color
= [](const std::string
&s
, bool background
) {
258 short result
= invalid_color_value
;
260 result
= COLOR_BLACK
;
263 else if (s
== "green")
264 result
= COLOR_GREEN
;
265 else if (s
== "yellow")
266 result
= COLOR_YELLOW
;
267 else if (s
== "blue")
269 else if (s
== "magenta")
270 result
= COLOR_MAGENTA
;
271 else if (s
== "cyan")
273 else if (s
== "white")
274 result
= COLOR_WHITE
;
275 else if (background
&& s
== "transparent")
276 result
= NC::Color::transparent
;
277 else if (background
&& s
== "current")
278 result
= NC::Color::current
;
279 else if (std::all_of(s
.begin(), s
.end(), isdigit
))
281 result
= atoi(s
.c_str());
282 if (result
< (background
? 0 : 1) || result
> 256)
283 result
= invalid_color_value
;
290 auto get_color
= [](std::istream
&is_
) {
292 while (!is_
.eof() && isalnum(is_
.peek()))
293 result
.push_back(is_
.get());
297 std::string sc
= get_color(is
);
301 else if (sc
== "end")
305 short fg
= get_single_color(sc
, false);
306 if (fg
== invalid_color_value
)
307 is
.setstate(std::ios::failbit
);
308 // Check if there is background color
309 else if (!is
.eof() && is
.peek() == '_')
313 short bg
= get_single_color(sc
, true);
314 if (bg
== invalid_color_value
)
315 is
.setstate(std::ios::failbit
);
320 c
= Color(fg
, NC::Color::current
);
325 NC::Format
reverseFormat(NC::Format fmt
)
329 case NC::Format::Bold
:
330 return NC::Format::NoBold
;
331 case NC::Format::NoBold
:
332 return NC::Format::Bold
;
333 case NC::Format::Underline
:
334 return NC::Format::NoUnderline
;
335 case NC::Format::NoUnderline
:
336 return NC::Format::Underline
;
337 case NC::Format::Reverse
:
338 return NC::Format::NoReverse
;
339 case NC::Format::NoReverse
:
340 return NC::Format::Reverse
;
341 case NC::Format::AltCharset
:
342 return NC::Format::NoAltCharset
;
343 case NC::Format::NoAltCharset
:
344 return NC::Format::AltCharset
;
346 // Unreachable, silence GCC.
354 bool supportEnabled
= false;
362 // save old highlight mouse tracking
363 std::printf("\e[?1001s");
364 // enable mouse tracking
365 std::printf("\e[?1000h");
366 // try to enable extended (urxvt) mouse tracking
367 std::printf("\e[?1015h");
368 // send the above to the terminal immediately
376 // disable extended (urxvt) mouse tracking
377 std::printf("\e[?1015l");
378 // disable mouse tracking
379 std::printf("\e[?1000l");
380 // restore old highlight mouse tracking
381 std::printf("\e[?1001r");
382 // send the above to the terminal immediately
388 void initScreen(bool enable_colors
, bool enable_mouse
)
391 if (has_colors() && enable_colors
)
394 use_default_colors();
395 color_pair_map
.resize(256 * 256, 0);
397 // Predefine pairs for colors with transparent background, all the other
398 // ones will be dynamically registered in Color::pairNumber when they're
400 color_pair_counter
= 1;
401 for (int fg
= 0; fg
< COLORS
; ++fg
, ++color_pair_counter
)
403 init_pair(color_pair_counter
, fg
, -1);
404 color_pair_map
[fg
] = color_pair_counter
;
414 Mouse::supportEnabled
= enable_mouse
;
417 // initialize readline (needed, otherwise we get segmentation
418 // fault on SIGWINCH). also, initialize first as doing this
419 // later erases keys bound with rl_bind_key for some users.
421 // disable autocompletion
422 rl_attempted_completion_function
= [](const char *, int, int) -> char ** {
423 rl_attempted_completion_over
= 1;
426 auto abort_prompt
= [](int, int) -> int {
431 // if ctrl-c or ctrl-g is pressed, abort the prompt
432 rl_bind_key('\3', abort_prompt
);
433 rl_bind_key('\7', abort_prompt
);
434 // do not change the state of the terminal
435 rl_prep_term_function
= nullptr;
436 rl_deprep_term_function
= nullptr;
437 // do not catch signals
438 rl_catch_signals
= 0;
439 rl_catch_sigwinch
= 0;
440 // overwrite readline callbacks
441 rl_getc_function
= rl::read_key
;
442 rl_redisplay_function
= rl::display_string
;
443 rl_startup_hook
= rl::add_base
;
464 Window::Window(size_t startx
, size_t starty
, size_t width
, size_t height
,
465 std::string title
, Color color
, Border border
)
471 m_window_timeout(-1),
472 m_border(std::move(border
)),
474 m_title(std::move(title
)),
475 m_escape_terminal_sequences(true),
477 m_underline_counter(0),
478 m_reverse_counter(0),
479 m_alt_charset_counter(0)
481 if (m_start_x
> size_t(COLS
)
482 || m_start_y
> size_t(LINES
)
483 || m_width
+m_start_x
> size_t(COLS
)
484 || m_height
+m_start_y
> size_t(LINES
))
485 throw std::logic_error("constructed window doesn't fit into the terminal");
494 if (!m_title
.empty())
500 m_window
= newpad(m_height
, m_width
);
501 wtimeout(m_window
, 0);
504 setColor(m_base_color
);
507 Window::Window(const Window
&rhs
)
508 : m_window(dupwin(rhs
.m_window
))
509 , m_start_x(rhs
.m_start_x
)
510 , m_start_y(rhs
.m_start_y
)
511 , m_width(rhs
.m_width
)
512 , m_height(rhs
.m_height
)
513 , m_window_timeout(rhs
.m_window_timeout
)
514 , m_color(rhs
.m_color
)
515 , m_base_color(rhs
.m_base_color
)
516 , m_border(rhs
.m_border
)
517 , m_prompt_hook(rhs
.m_prompt_hook
)
518 , m_title(rhs
.m_title
)
519 , m_color_stack(rhs
.m_color_stack
)
520 , m_input_queue(rhs
.m_input_queue
)
522 , m_escape_terminal_sequences(rhs
.m_escape_terminal_sequences
)
523 , m_bold_counter(rhs
.m_bold_counter
)
524 , m_underline_counter(rhs
.m_underline_counter
)
525 , m_reverse_counter(rhs
.m_reverse_counter
)
526 , m_alt_charset_counter(rhs
.m_alt_charset_counter
)
531 Window::Window(Window
&&rhs
)
532 : m_window(rhs
.m_window
)
533 , m_start_x(rhs
.m_start_x
)
534 , m_start_y(rhs
.m_start_y
)
535 , m_width(rhs
.m_width
)
536 , m_height(rhs
.m_height
)
537 , m_window_timeout(rhs
.m_window_timeout
)
538 , m_color(rhs
.m_color
)
539 , m_base_color(rhs
.m_base_color
)
540 , m_border(rhs
.m_border
)
541 , m_prompt_hook(rhs
.m_prompt_hook
)
542 , m_title(std::move(rhs
.m_title
))
543 , m_color_stack(std::move(rhs
.m_color_stack
))
544 , m_input_queue(std::move(rhs
.m_input_queue
))
545 , m_fds(std::move(rhs
.m_fds
))
546 , m_escape_terminal_sequences(rhs
.m_escape_terminal_sequences
)
547 , m_bold_counter(rhs
.m_bold_counter
)
548 , m_underline_counter(rhs
.m_underline_counter
)
549 , m_reverse_counter(rhs
.m_reverse_counter
)
550 , m_alt_charset_counter(rhs
.m_alt_charset_counter
)
552 rhs
.m_window
= nullptr;
555 Window
&Window::operator=(Window rhs
)
557 std::swap(m_window
, rhs
.m_window
);
558 std::swap(m_start_x
, rhs
.m_start_x
);
559 std::swap(m_start_y
, rhs
.m_start_y
);
560 std::swap(m_width
, rhs
.m_width
);
561 std::swap(m_height
, rhs
.m_height
);
562 std::swap(m_window_timeout
, rhs
.m_window_timeout
);
563 std::swap(m_color
, rhs
.m_color
);
564 std::swap(m_base_color
, rhs
.m_base_color
);
565 std::swap(m_border
, rhs
.m_border
);
566 std::swap(m_prompt_hook
, rhs
.m_prompt_hook
);
567 std::swap(m_title
, rhs
.m_title
);
568 std::swap(m_color_stack
, rhs
.m_color_stack
);
569 std::swap(m_input_queue
, rhs
.m_input_queue
);
570 std::swap(m_fds
, rhs
.m_fds
);
571 std::swap(m_escape_terminal_sequences
, rhs
.m_escape_terminal_sequences
);
572 std::swap(m_bold_counter
, rhs
.m_bold_counter
);
573 std::swap(m_underline_counter
, rhs
.m_underline_counter
);
574 std::swap(m_reverse_counter
, rhs
.m_reverse_counter
);
575 std::swap(m_alt_charset_counter
, rhs
.m_alt_charset_counter
);
584 void Window::setColor(Color c
)
588 if (c
!= Color::Default
)
590 assert(!c
.currentBackground());
591 wcolor_set(m_window
, c
.pairNumber(), nullptr);
594 wcolor_set(m_window
, m_base_color
.pairNumber(), nullptr);
595 m_color
= std::move(c
);
598 void Window::setBaseColor(const Color
&color
)
600 if (color
.currentBackground())
601 m_base_color
= Color(color
.foreground(), Color::transparent
);
603 m_base_color
= color
;
606 void Window::setBorder(Border border
)
608 if (!border
&& m_border
)
614 recreate(m_width
, m_height
);
616 else if (border
&& !m_border
)
622 recreate(m_width
, m_height
);
627 void Window::setTitle(const std::string
&new_title
)
629 if (!new_title
.empty() && m_title
.empty())
633 recreate(m_width
, m_height
);
635 else if (new_title
.empty() && !m_title
.empty())
639 recreate(m_width
, m_height
);
644 void Window::recreate(size_t width
, size_t height
)
647 m_window
= newpad(height
, width
);
648 wtimeout(m_window
, 0);
652 void Window::moveTo(size_t new_x
, size_t new_y
)
661 if (!m_title
.empty())
665 void Window::adjustDimensions(size_t width
, size_t height
)
672 if (!m_title
.empty())
678 void Window::resize(size_t new_width
, size_t new_height
)
680 adjustDimensions(new_width
, new_height
);
681 recreate(m_width
, m_height
);
684 void Window::refreshBorder() const
688 size_t start_x
= getStartX(), start_y
= getStarty();
689 size_t width
= getWidth(), height
= getHeight();
690 color_set(m_border
->pairNumber(), nullptr);
691 attron(A_ALTCHARSET
);
693 mvaddch(start_y
, start_x
, 'l');
694 mvaddch(start_y
, start_x
+width
-1, 'k');
695 mvaddch(start_y
+height
-1, start_x
, 'm');
696 mvaddch(start_y
+height
-1, start_x
+width
-1, 'j');
698 mvhline(start_y
, start_x
+1, 'q', width
-2);
699 mvhline(start_y
+height
-1, start_x
+1, 'q', width
-2);
700 mvvline(start_y
+1, start_x
, 'x', height
-2);
701 mvvline(start_y
+1, start_x
+width
-1, 'x', height
-2);
702 if (!m_title
.empty())
704 mvaddch(start_y
+2, start_x
, 't');
705 mvaddch(start_y
+2, start_x
+width
-1, 'u');
707 attroff(A_ALTCHARSET
);
710 color_set(m_base_color
.pairNumber(), nullptr);
711 if (!m_title
.empty())
714 mvhline(m_start_y
-2, m_start_x
, ' ', m_width
);
716 mvaddstr(m_start_y
-2, m_start_x
, m_title
.c_str());
719 mvhline(m_start_y
-1, m_start_x
, 0, m_width
);
725 void Window::display()
731 void Window::refresh()
733 prefresh(m_window
, 0, 0, m_start_y
, m_start_x
, m_start_y
+m_height
-1, m_start_x
+m_width
-1);
739 setColor(m_base_color
);
742 void Window::bold(bool bold_state
) const
744 (bold_state
? wattron
: wattroff
)(m_window
, A_BOLD
);
747 void Window::underline(bool underline_state
) const
749 (underline_state
? wattron
: wattroff
)(m_window
, A_UNDERLINE
);
752 void Window::reverse(bool reverse_state
) const
754 (reverse_state
? wattron
: wattroff
)(m_window
, A_REVERSE
);
757 void Window::altCharset(bool altcharset_state
) const
759 (altcharset_state
? wattron
: wattroff
)(m_window
, A_ALTCHARSET
);
762 void Window::setTimeout(int timeout
)
764 m_window_timeout
= timeout
;
767 void Window::addFDCallback(int fd
, void (*callback
)())
769 m_fds
.push_back(std::make_pair(fd
, callback
));
772 void Window::clearFDCallbacksList()
777 bool Window::FDCallbacksListEmpty() const
779 return m_fds
.empty();
782 Key::Type
Window::getInputChar(int key
)
784 if (!m_escape_terminal_sequences
|| key
!= Key::Escape
)
786 auto define_mouse_event
= [this](int type
) {
790 m_mouse_event
.bstate
= BUTTON1_PRESSED
;
793 m_mouse_event
.bstate
= BUTTON2_PRESSED
;
796 m_mouse_event
.bstate
= BUTTON3_PRESSED
;
799 m_mouse_event
.bstate
= BUTTON4_PRESSED
;
802 m_mouse_event
.bstate
= BUTTON5_PRESSED
;
808 m_mouse_event
.bstate
|= BUTTON_SHIFT
;
810 m_mouse_event
.bstate
|= BUTTON_ALT
;
812 m_mouse_event
.bstate
|= BUTTON_CTRL
;
813 if (m_mouse_event
.x
< 0 || m_mouse_event
.x
>= COLS
)
815 if (m_mouse_event
.y
< 0 || m_mouse_event
.y
>= LINES
)
819 auto get_xterm_modifier_key
= [](int ch
) {
824 modifier
= Key::Shift
;
830 modifier
= Key::Alt
| Key::Shift
;
833 modifier
= Key::Ctrl
;
836 modifier
= Key::Ctrl
| Key::Shift
;
839 modifier
= Key::Alt
| Key::Ctrl
;
842 modifier
= Key::Alt
| Key::Ctrl
| Key::Shift
;
845 modifier
= Key::None
;
849 auto parse_number
= [this](int &result
) {
853 x
= wgetch(m_window
);
856 result
= result
*10 + x
- '0';
859 key
= wgetch(m_window
);
863 return Key::Shift
| Key::Tab
;
865 key
= wgetch(m_window
);
884 return Key::Ctrl
| Key::Up
;
886 return Key::Ctrl
| Key::Down
;
888 return Key::Ctrl
| Key::Right
;
890 return Key::Ctrl
| Key::Left
;
904 key
= wgetch(m_window
);
908 return Key::Shift
| Key::Up
;
910 return Key::Shift
| Key::Down
;
912 return Key::Shift
| Key::Right
;
914 return Key::Shift
| Key::Left
;
927 case 'M': // standard mouse event
929 key
= wgetch(m_window
);
930 int raw_x
= wgetch(m_window
);
931 int raw_y
= wgetch(m_window
);
932 // support coordinates up to 255
933 m_mouse_event
.x
= (raw_x
- 33) & 0xff;
934 m_mouse_event
.y
= (raw_y
- 33) & 0xff;
935 return define_mouse_event(key
);
938 return Key::Shift
| Key::Tab
;
939 case '[': // F1 to F5 in tty
940 key
= wgetch(m_window
);
956 case '1': case '2': case '3':
957 case '4': case '5': case '6':
958 case '7': case '8': case '9':
961 int delim
= parse_number(key
);
962 if (key
>= 2 && key
<= 8)
968 modifier
= Key::Null
;
971 modifier
= Key::Ctrl
;
974 modifier
= Key::Shift
;
977 modifier
= Key::Ctrl
| Key::Shift
;
979 case ';': // xterm insert/delete/page up/page down
981 int local_key
= wgetch(m_window
);
982 modifier
= get_xterm_modifier_key(local_key
);
983 local_key
= wgetch(m_window
);
984 if (local_key
!= '~' || (key
!= 2 && key
!= 3 && key
!= 5 && key
!= 6))
994 return modifier
| Key::Insert
;
996 return modifier
| Key::Delete
;
998 return modifier
| Key::End
;
1000 return modifier
| Key::PageUp
;
1002 return modifier
| Key::PageDown
;
1004 return modifier
| Key::Home
;
1006 return modifier
| Key::End
;
1008 std::cerr
<< "Unreachable code, aborting.\n";
1030 case 17: // not a typo
1040 case 23: // not a typo
1053 key
= wgetch(m_window
);
1054 Key::Type modifier
= get_xterm_modifier_key(key
);
1055 if (modifier
== Key::None
)
1057 key
= wgetch(m_window
);
1061 return modifier
| Key::Up
;
1063 return modifier
| Key::Down
;
1065 return modifier
| Key::Right
;
1067 return modifier
| Key::Left
;
1069 return modifier
| Key::End
;
1071 return modifier
| Key::Home
;
1076 default: // urxvt mouse
1077 m_mouse_event
.x
= 0;
1078 delim
= parse_number(m_mouse_event
.x
);
1081 m_mouse_event
.y
= 0;
1082 delim
= parse_number(m_mouse_event
.y
);
1087 return define_mouse_event(key
);
1098 default: // alt + something
1100 auto key_prim
= getInputChar(key
);
1101 if (key_prim
!= Key::None
)
1102 return Key::Alt
| key_prim
;
1108 Key::Type
Window::readKey()
1111 // if there are characters in input queue,
1112 // get them and return immediately.
1113 if (!m_input_queue
.empty())
1115 result
= m_input_queue
.front();
1116 m_input_queue
.pop();
1122 FD_SET(STDIN_FILENO
, &fds_read
);
1123 timeval timeout
= { m_window_timeout
/1000, (m_window_timeout
%1000)*1000 };
1125 int fd_max
= STDIN_FILENO
;
1126 for (const auto &fd
: m_fds
)
1128 if (fd
.first
> fd_max
)
1130 FD_SET(fd
.first
, &fds_read
);
1133 auto tv_addr
= m_window_timeout
< 0 ? nullptr : &timeout
;
1134 int res
= select(fd_max
+1, &fds_read
, nullptr, nullptr, tv_addr
);
1137 if (FD_ISSET(STDIN_FILENO
, &fds_read
))
1139 int key
= wgetch(m_window
);
1143 result
= getInputChar(key
);
1148 for (const auto &fd
: m_fds
)
1149 if (FD_ISSET(fd
.first
, &fds_read
))
1157 void Window::pushChar(const Key::Type ch
)
1159 m_input_queue
.push(ch
);
1162 std::string
Window::prompt(const std::string
&base
, size_t width
, bool encrypted
)
1166 rl::aborted
= false;
1168 getyx(m_window
, rl::start_y
, rl::start_x
);
1169 rl::width
= std::min(m_width
-rl::start_x
-1, width
-1);
1170 rl::encrypted
= encrypted
;
1171 rl::base
= base
.c_str();
1175 m_escape_terminal_sequences
= false;
1176 char *input
= readline(nullptr);
1177 m_escape_terminal_sequences
= true;
1180 if (input
!= nullptr)
1182 #ifdef HAVE_READLINE_HISTORY_H
1183 if (!encrypted
&& input
[0] != 0)
1185 #endif // HAVE_READLINE_HISTORY_H
1191 throw PromptAborted(std::move(result
));
1196 void Window::goToXY(int x
, int y
)
1198 wmove(m_window
, y
, x
);
1203 return getcurx(m_window
);
1208 return getcury(m_window
);
1211 bool Window::hasCoords(int &x
, int &y
)
1213 return wmouse_trafo(m_window
, &y
, &x
, 0);
1216 bool Window::runPromptHook(const char *arg
, bool *done
) const
1220 bool continue_
= m_prompt_hook(arg
);
1221 if (done
!= nullptr)
1229 size_t Window::getWidth() const
1237 size_t Window::getHeight() const
1239 size_t height
= m_height
;
1242 if (!m_title
.empty())
1247 size_t Window::getStartX() const
1255 size_t Window::getStarty() const
1257 size_t starty
= m_start_y
;
1260 if (!m_title
.empty())
1265 const std::string
&Window::getTitle() const
1270 const Color
&Window::getColor() const
1275 const Border
&Window::getBorder() const
1280 int Window::getTimeout() const
1282 return m_window_timeout
;
1285 const MEVENT
&Window::getMouseEvent()
1287 return m_mouse_event
;
1290 void Window::scroll(Scroll where
)
1293 scrollok(m_window
, 1);
1300 wscrl(m_window
, -1);
1302 case Scroll::PageUp
:
1303 wscrl(m_window
, m_width
);
1305 case Scroll::PageDown
:
1306 wscrl(m_window
, -m_width
);
1312 scrollok(m_window
, 0);
1316 Window
&Window::operator<<(const Color
&c
)
1320 while (!m_color_stack
.empty())
1321 m_color_stack
.pop();
1322 setColor(m_base_color
);
1326 if (!m_color_stack
.empty())
1327 m_color_stack
.pop();
1328 if (!m_color_stack
.empty())
1329 setColor(m_color_stack
.top());
1331 setColor(m_base_color
);
1335 if (c
.currentBackground())
1337 short background
= m_color
.isDefault()
1338 ? Color::transparent
1339 : m_color
.background();
1340 Color cc
= Color(c
.foreground(), background
);
1342 m_color_stack
.push(cc
);
1347 m_color_stack
.push(c
);
1353 Window
&Window::operator<<(Format format
)
1355 auto increase_flag
= [](Window
&w
, int &flag
, auto set
) {
1359 auto decrease_flag
= [](Window
&w
, int &flag
, auto set
) {
1370 increase_flag(*this, m_bold_counter
, &Window::bold
);
1372 case Format::NoBold
:
1373 decrease_flag(*this, m_bold_counter
, &Window::bold
);
1375 case Format::Underline
:
1376 increase_flag(*this, m_underline_counter
, &Window::underline
);
1378 case Format::NoUnderline
:
1379 decrease_flag(*this, m_underline_counter
, &Window::underline
);
1381 case Format::Reverse
:
1382 increase_flag(*this, m_reverse_counter
, &Window::reverse
);
1384 case Format::NoReverse
:
1385 decrease_flag(*this, m_reverse_counter
, &Window::reverse
);
1387 case Format::AltCharset
:
1388 increase_flag(*this, m_alt_charset_counter
, &Window::altCharset
);
1390 case Format::NoAltCharset
:
1391 decrease_flag(*this, m_alt_charset_counter
, &Window::altCharset
);
1397 Window
&Window::operator<<(TermManip tm
)
1401 case TermManip::ClearToEOL
:
1403 auto x
= getX(), y
= getY();
1404 mvwhline(m_window
, y
, x
, ' ', m_width
-x
);
1412 Window
&Window::operator<<(const XY
&coords
)
1414 goToXY(coords
.x
, coords
.y
);
1418 Window
&Window::operator<<(const char *s
)
1420 waddstr(m_window
, s
);
1424 Window
&Window::operator<<(char c
)
1426 // Might cause problem similar to
1427 // https://github.com/arybczak/ncmpcpp/issues/21, enable for testing as the
1428 // code in the ticket supposed to be culprit was rewritten.
1429 waddnstr(m_window
, &c
, 1);
1430 //wprintw(m_window, "%c", c);
1434 Window
&Window::operator<<(const wchar_t *ws
)
1436 waddwstr(m_window
, ws
);
1440 Window
&Window::operator<<(wchar_t wc
)
1442 waddnwstr(m_window
, &wc
, 1);
1446 Window
&Window::operator<<(int i
)
1448 wprintw(m_window
, "%d", i
);
1452 Window
&Window::operator<<(double d
)
1454 wprintw(m_window
, "%f", d
);
1458 Window
&Window::operator<<(const std::string
&s
)
1460 waddnstr(m_window
, s
.c_str(), s
.length());
1464 Window
&Window::operator<<(const std::wstring
&ws
)
1466 waddnwstr(m_window
, ws
.c_str(), ws
.length());
1470 Window
&Window::operator<<(size_t s
)
1472 wprintw(m_window
, "%zu", s
);