1 /***************************************************************************
2 * Copyright (C) 2008-2014 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"
36 struct ScopedWindowTimeout
38 ScopedWindowTimeout(WINDOW
*w
, int init_timeout
, int term_timeout
)
39 : m_w(w
), m_term_timeout(term_timeout
) {
40 wtimeout(w
, init_timeout
);
42 ~ScopedWindowTimeout() {
43 wtimeout(m_w
, m_term_timeout
);
70 if (w
->runPromptHook(rl_line_buffer
, &done
))
77 w
->goToXY(x
, start_y
);
80 result
= w
->readKey();
81 if (!w
->FDCallbacksListEmpty())
83 w
->goToXY(x
, start_y
);
87 while (result
== ERR
);
93 auto print_char
= [](wchar_t wc
) {
99 auto print_string
= [](wchar_t *ws
, size_t len
) {
101 for (size_t i
= 0; i
< len
; ++i
)
106 auto narrow_to_wide
= [](wchar_t *dest
, const char *src
, size_t n
) {
108 // convert the string and substitute invalid multibyte chars with dots.
109 for (size_t i
= 0; i
< n
;)
111 int ret
= mbtowc(&dest
[result
], &src
[i
], n
-i
);
124 throw std::runtime_error("mbtowc: unexpected return value");
129 // copy the part of the string that is before the cursor to pre_pos
130 char pt
= rl_line_buffer
[rl_point
];
131 rl_line_buffer
[rl_point
] = 0;
132 wchar_t pre_pos
[rl_point
+1];
133 pre_pos
[narrow_to_wide(pre_pos
, rl_line_buffer
, rl_point
)] = 0;
134 rl_line_buffer
[rl_point
] = pt
;
136 int pos
= wcswidth(pre_pos
, rl_point
);
140 // clear the area for the string
141 mvwhline(w
->raw(), start_y
, start_x
, ' ', width
+1);
143 w
->goToXY(start_x
, start_y
);
144 if (size_t(pos
) <= width
)
146 // if the current position in the string is not bigger than allowed
147 // width, print the part of the string before cursor position...
149 print_string(pre_pos
, pos
);
151 // ...and then print the rest char-by-char until there is no more area
152 wchar_t post_pos
[rl_end
-rl_point
+1];
153 post_pos
[narrow_to_wide(post_pos
, rl_line_buffer
+rl_point
, rl_end
-rl_point
)] = 0;
156 for (wchar_t *c
= post_pos
; *c
!= 0; ++c
)
175 // if the current position in the string is bigger than allowed
176 // width, we always keep the cursor at the end of the line (it
177 // would be nice to have more flexible scrolling, but for now
178 // let's stick to that) by cutting the beginning of the part
179 // of the string before the cursor until it fits the area.
181 wchar_t *mod_pre_pos
= pre_pos
;
182 while (*mod_pre_pos
!= 0)
185 int n
= wcwidth(*mod_pre_pos
);
190 if (size_t(pos
) <= width
)
193 print_string(mod_pre_pos
, pos
);
195 w
->goToXY(start_x
+pos
, start_y
);
200 rl_insert_text(base
);
209 const short Color::transparent
= -1;
210 const short Color::previous
= -2;
212 Color
Color::Default(0, 0, true, false);
213 Color
Color::Black(COLOR_BLACK
, Color::transparent
);
214 Color
Color::Red(COLOR_RED
, Color::transparent
);
215 Color
Color::Green(COLOR_GREEN
, Color::transparent
);
216 Color
Color::Yellow(COLOR_YELLOW
, Color::transparent
);
217 Color
Color::Blue(COLOR_BLUE
, Color::transparent
);
218 Color
Color::Magenta(COLOR_MAGENTA
, Color::transparent
);
219 Color
Color::Cyan(COLOR_CYAN
, Color::transparent
);
220 Color
Color::White(COLOR_WHITE
, Color::transparent
);
221 Color
Color::End(0, 0, false, true);
223 int Color::pairNumber() const
228 else if (previousBackground())
229 throw std::logic_error("color depends on the previous background value");
231 throw std::logic_error("'end' doesn't have a corresponding pair number");
234 // colors start with 0, but pairs start with 1. additionally
235 // first pairs are for transparent background, which has a
236 // value of -1, so we need to add 1 to both foreground and
238 result
= background() + 1;
240 result
+= foreground() + 1;
245 std::istream
&operator>>(std::istream
&is
, Color
&c
)
247 auto get_single_color
= [](const std::string
&s
, bool background
) {
250 result
= COLOR_BLACK
;
253 else if (s
== "green")
254 result
= COLOR_GREEN
;
255 else if (s
== "yellow")
256 result
= COLOR_YELLOW
;
257 else if (s
== "blue")
259 else if (s
== "magenta")
260 result
= COLOR_MAGENTA
;
261 else if (s
== "cyan")
263 else if (s
== "white")
264 result
= COLOR_WHITE
;
265 else if (background
&& s
== "previous")
266 result
= NC::Color::previous
;
267 else if (std::all_of(s
.begin(), s
.end(), isdigit
))
269 result
= atoi(s
.c_str());
270 if (result
< 1 || result
> 256)
281 else if (sc
== "end")
285 short value
= get_single_color(sc
, false);
287 c
= Color(value
, NC::Color::transparent
);
290 size_t underscore
= sc
.find('_');
291 if (underscore
!= std::string::npos
)
293 short fg
= get_single_color(sc
.substr(0, underscore
), false);
294 short bg
= get_single_color(sc
.substr(underscore
+1), true);
295 if (fg
!= -1 && bg
!= -1)
298 is
.setstate(std::ios::failbit
);
301 is
.setstate(std::ios::failbit
);
311 bool supportEnabled
= false;
319 // save old highlight mouse tracking
320 std::printf("\e[?1001s");
321 // enable mouse tracking
322 std::printf("\e[?1000h");
323 // try to enable extended (urxvt) mouse tracking
324 std::printf("\e[?1015h");
325 // send the above to the terminal immediately
333 // disable extended (urxvt) mouse tracking
334 std::printf("\e[?1015l");
335 // disable mouse tracking
336 std::printf("\e[?1000l");
337 // restore old highlight mouse tracking
338 std::printf("\e[?1001r");
339 // send the above to the terminal immediately
345 void initScreen(bool enable_colors
, bool enable_mouse
)
348 if (has_colors() && enable_colors
)
351 use_default_colors();
353 for (int bg
= -1; bg
< COLORS
; ++bg
)
355 for (int fg
= 0; npair
< COLOR_PAIRS
&& fg
< COLORS
; ++fg
, ++npair
)
356 init_pair(npair
, fg
, bg
);
365 Mouse::supportEnabled
= enable_mouse
;
368 // initialize readline (needed, otherwise we get segmentation
369 // fault on SIGWINCH). also, initialize first as doing this
370 // later erases keys bound with rl_bind_key for some users.
372 // disable autocompletion
373 rl_attempted_completion_function
= [](const char *, int, int) -> char ** {
374 rl_attempted_completion_over
= 1;
377 auto abort_prompt
= [](int, int) -> int {
382 // if ctrl-c or ctrl-g is pressed, abort the prompt
383 rl_bind_key('\3', abort_prompt
);
384 rl_bind_key('\7', abort_prompt
);
385 // do not change the state of the terminal
386 rl_prep_term_function
= nullptr;
387 rl_deprep_term_function
= nullptr;
388 // do not catch signals
389 rl_catch_signals
= 0;
390 // overwrite readline callbacks
391 rl_getc_function
= rl::read_key
;
392 rl_redisplay_function
= rl::display_string
;
393 rl_startup_hook
= rl::add_base
;
403 Window::Window(size_t startx
,
415 m_window_timeout(-1),
418 m_border(std::move(border
)),
420 m_title(std::move(title
)),
421 m_escape_terminal_sequences(true),
423 m_underline_counter(0),
424 m_reverse_counter(0),
425 m_alt_charset_counter(0)
427 if (m_start_x
> size_t(COLS
)
428 || m_start_y
> size_t(LINES
)
429 || m_width
+m_start_x
> size_t(COLS
)
430 || m_height
+m_start_y
> size_t(LINES
))
431 throw std::logic_error("constructed window doesn't fit into the terminal");
440 if (!m_title
.empty())
446 m_window
= newpad(m_height
, m_width
);
451 Window::Window(const Window
&rhs
)
452 : m_window(dupwin(rhs
.m_window
))
453 , m_start_x(rhs
.m_start_x
)
454 , m_start_y(rhs
.m_start_y
)
455 , m_width(rhs
.m_width
)
456 , m_height(rhs
.m_height
)
457 , m_window_timeout(rhs
.m_window_timeout
)
458 , m_color(rhs
.m_color
)
459 , m_base_color(rhs
.m_base_color
)
460 , m_border(rhs
.m_border
)
461 , m_prompt_hook(rhs
.m_prompt_hook
)
462 , m_title(rhs
.m_title
)
463 , m_color_stack(rhs
.m_color_stack
)
464 , m_input_queue(rhs
.m_input_queue
)
466 , m_escape_terminal_sequences(rhs
.m_escape_terminal_sequences
)
467 , m_bold_counter(rhs
.m_bold_counter
)
468 , m_underline_counter(rhs
.m_underline_counter
)
469 , m_reverse_counter(rhs
.m_reverse_counter
)
470 , m_alt_charset_counter(rhs
.m_alt_charset_counter
)
474 Window::Window(Window
&&rhs
)
475 : m_window(rhs
.m_window
)
476 , m_start_x(rhs
.m_start_x
)
477 , m_start_y(rhs
.m_start_y
)
478 , m_width(rhs
.m_width
)
479 , m_height(rhs
.m_height
)
480 , m_window_timeout(rhs
.m_window_timeout
)
481 , m_color(rhs
.m_color
)
482 , m_base_color(rhs
.m_base_color
)
483 , m_border(rhs
.m_border
)
484 , m_prompt_hook(rhs
.m_prompt_hook
)
485 , m_title(std::move(rhs
.m_title
))
486 , m_color_stack(std::move(rhs
.m_color_stack
))
487 , m_input_queue(std::move(rhs
.m_input_queue
))
488 , m_fds(std::move(rhs
.m_fds
))
489 , m_escape_terminal_sequences(rhs
.m_escape_terminal_sequences
)
490 , m_bold_counter(rhs
.m_bold_counter
)
491 , m_underline_counter(rhs
.m_underline_counter
)
492 , m_reverse_counter(rhs
.m_reverse_counter
)
493 , m_alt_charset_counter(rhs
.m_alt_charset_counter
)
495 rhs
.m_window
= nullptr;
498 Window
&Window::operator=(Window rhs
)
500 std::swap(m_window
, rhs
.m_window
);
501 std::swap(m_start_x
, rhs
.m_start_x
);
502 std::swap(m_start_y
, rhs
.m_start_y
);
503 std::swap(m_width
, rhs
.m_width
);
504 std::swap(m_height
, rhs
.m_height
);
505 std::swap(m_window_timeout
, rhs
.m_window_timeout
);
506 std::swap(m_color
, rhs
.m_color
);
507 std::swap(m_base_color
, rhs
.m_base_color
);
508 std::swap(m_border
, rhs
.m_border
);
509 std::swap(m_prompt_hook
, rhs
.m_prompt_hook
);
510 std::swap(m_title
, rhs
.m_title
);
511 std::swap(m_color_stack
, rhs
.m_color_stack
);
512 std::swap(m_input_queue
, rhs
.m_input_queue
);
513 std::swap(m_fds
, rhs
.m_fds
);
514 std::swap(m_escape_terminal_sequences
, rhs
.m_escape_terminal_sequences
);
515 std::swap(m_bold_counter
, rhs
.m_bold_counter
);
516 std::swap(m_underline_counter
, rhs
.m_underline_counter
);
517 std::swap(m_reverse_counter
, rhs
.m_reverse_counter
);
518 std::swap(m_alt_charset_counter
, rhs
.m_alt_charset_counter
);
527 void Window::setColor(Color c
)
531 if (c
!= Color::Default
)
533 if (c
.previousBackground())
534 c
= Color(c
.foreground(), m_color
.background());
535 wcolor_set(m_window
, c
.pairNumber(), nullptr);
538 wcolor_set(m_window
, m_base_color
.pairNumber(), nullptr);
539 m_color
= std::move(c
);
542 void Window::setBaseColor(Color c
)
544 m_base_color
= std::move(c
);
547 void Window::setBorder(Border border
)
549 if (!border
&& m_border
)
555 recreate(m_width
, m_height
);
557 else if (border
&& !m_border
)
563 recreate(m_width
, m_height
);
568 void Window::setTitle(const std::string
&new_title
)
570 if (!new_title
.empty() && m_title
.empty())
574 recreate(m_width
, m_height
);
576 else if (new_title
.empty() && !m_title
.empty())
580 recreate(m_width
, m_height
);
585 void Window::recreate(size_t width
, size_t height
)
588 m_window
= newpad(height
, width
);
589 setTimeout(m_window_timeout
);
593 void Window::moveTo(size_t new_x
, size_t new_y
)
602 if (!m_title
.empty())
606 void Window::adjustDimensions(size_t width
, size_t height
)
613 if (!m_title
.empty())
619 void Window::resize(size_t new_width
, size_t new_height
)
621 adjustDimensions(new_width
, new_height
);
622 recreate(m_width
, m_height
);
625 void Window::refreshBorder() const
629 size_t start_x
= getStartX(), start_y
= getStarty();
630 size_t width
= getWidth(), height
= getHeight();
631 color_set(m_border
->pairNumber(), nullptr);
632 attron(A_ALTCHARSET
);
634 mvaddch(start_y
, start_x
, 'l');
635 mvaddch(start_y
, start_x
+width
-1, 'k');
636 mvaddch(start_y
+height
-1, start_x
, 'm');
637 mvaddch(start_y
+height
-1, start_x
+width
-1, 'j');
639 mvhline(start_y
, start_x
+1, 'q', width
-2);
640 mvhline(start_y
+height
-1, start_x
+1, 'q', width
-2);
641 mvvline(start_y
+1, start_x
, 'x', height
-2);
642 mvvline(start_y
+1, start_x
+width
-1, 'x', height
-2);
643 if (!m_title
.empty())
645 mvaddch(start_y
+2, start_x
, 't');
646 mvaddch(start_y
+2, start_x
+width
-1, 'u');
648 attroff(A_ALTCHARSET
);
651 color_set(m_base_color
.pairNumber(), nullptr);
652 if (!m_title
.empty())
655 mvhline(m_start_y
-2, m_start_x
, ' ', m_width
);
657 mvaddstr(m_start_y
-2, m_start_x
, m_title
.c_str());
660 mvhline(m_start_y
-1, m_start_x
, 0, m_width
);
666 void Window::display()
672 void Window::refresh()
674 prefresh(m_window
, 0, 0, m_start_y
, m_start_x
, m_start_y
+m_height
-1, m_start_x
+m_width
-1);
682 void Window::bold(bool bold_state
) const
684 (bold_state
? wattron
: wattroff
)(m_window
, A_BOLD
);
687 void Window::underline(bool underline_state
) const
689 (underline_state
? wattron
: wattroff
)(m_window
, A_UNDERLINE
);
692 void Window::reverse(bool reverse_state
) const
694 (reverse_state
? wattron
: wattroff
)(m_window
, A_REVERSE
);
697 void Window::altCharset(bool altcharset_state
) const
699 (altcharset_state
? wattron
: wattroff
)(m_window
, A_ALTCHARSET
);
702 void Window::setTimeout(int timeout
)
704 if (timeout
!= m_window_timeout
)
706 m_window_timeout
= timeout
;
707 wtimeout(m_window
, timeout
);
711 void Window::addFDCallback(int fd
, void (*callback
)())
713 m_fds
.push_back(std::make_pair(fd
, callback
));
716 void Window::clearFDCallbacksList()
721 bool Window::FDCallbacksListEmpty() const
723 return m_fds
.empty();
726 Key::Type
Window::getInputChar(int key
)
728 if (!m_escape_terminal_sequences
|| key
!= Key::Escape
)
730 auto define_mouse_event
= [this](int type
) {
734 m_mouse_event
.bstate
= BUTTON1_PRESSED
;
737 m_mouse_event
.bstate
= BUTTON2_PRESSED
;
740 m_mouse_event
.bstate
= BUTTON3_PRESSED
;
743 m_mouse_event
.bstate
= BUTTON4_PRESSED
;
746 m_mouse_event
.bstate
= BUTTON5_PRESSED
;
752 m_mouse_event
.bstate
|= BUTTON_SHIFT
;
754 m_mouse_event
.bstate
|= BUTTON_ALT
;
756 m_mouse_event
.bstate
|= BUTTON_CTRL
;
757 if (m_mouse_event
.x
< 0 || m_mouse_event
.x
>= COLS
)
759 if (m_mouse_event
.y
< 0 || m_mouse_event
.y
>= LINES
)
763 auto get_xterm_modifier_key
= [](int ch
) {
768 modifier
= Key::Shift
;
774 modifier
= Key::Alt
| Key::Shift
;
777 modifier
= Key::Ctrl
;
780 modifier
= Key::Ctrl
| Key::Shift
;
783 modifier
= Key::Alt
| Key::Ctrl
;
786 modifier
= Key::Alt
| Key::Ctrl
| Key::Shift
;
789 modifier
= Key::None
;
793 auto parse_number
= [this](int &result
) {
797 x
= wgetch(m_window
);
800 result
= result
*10 + x
- '0';
803 ScopedWindowTimeout
swt(m_window
, 0, m_window_timeout
);
804 key
= wgetch(m_window
);
808 return Key::Shift
| Key::Tab
;
810 key
= wgetch(m_window
);
829 return Key::Ctrl
| Key::Up
;
831 return Key::Ctrl
| Key::Down
;
833 return Key::Ctrl
| Key::Right
;
835 return Key::Ctrl
| Key::Left
;
849 key
= wgetch(m_window
);
853 return Key::Shift
| Key::Up
;
855 return Key::Shift
| Key::Down
;
857 return Key::Shift
| Key::Right
;
859 return Key::Shift
| Key::Left
;
872 case 'M': // standard mouse event
874 key
= wgetch(m_window
);
875 int raw_x
= wgetch(m_window
);
876 int raw_y
= wgetch(m_window
);
877 // support coordinates up to 255
878 m_mouse_event
.x
= (raw_x
- 33) & 0xff;
879 m_mouse_event
.y
= (raw_y
- 33) & 0xff;
880 return define_mouse_event(key
);
883 return Key::Shift
| Key::Tab
;
884 case '[': // F1 to F5 in tty
885 key
= wgetch(m_window
);
901 case '1': case '2': case '3':
902 case '4': case '5': case '6':
903 case '7': case '8': case '9':
906 int delim
= parse_number(key
);
907 if (key
>= 2 && key
<= 8)
913 modifier
= Key::Null
;
916 modifier
= Key::Ctrl
;
919 modifier
= Key::Shift
;
922 modifier
= Key::Ctrl
| Key::Shift
;
924 case ';': // xterm insert/delete/page up/page down
926 int local_key
= wgetch(m_window
);
927 modifier
= get_xterm_modifier_key(local_key
);
928 local_key
= wgetch(m_window
);
929 if (local_key
!= '~' || (key
!= 2 && key
!= 3 && key
!= 5 && key
!= 6))
939 return modifier
| Key::Insert
;
941 return modifier
| Key::Delete
;
943 return modifier
| Key::End
;
945 return modifier
| Key::PageUp
;
947 return modifier
| Key::PageDown
;
949 return modifier
| Key::Home
;
951 return modifier
| Key::End
;
953 std::cerr
<< "Unreachable code, aborting.\n";
975 case 17: // not a typo
985 case 23: // not a typo
998 key
= wgetch(m_window
);
999 Key::Type modifier
= get_xterm_modifier_key(key
);
1000 if (modifier
== Key::None
)
1002 key
= wgetch(m_window
);
1006 return modifier
| Key::Up
;
1008 return modifier
| Key::Down
;
1010 return modifier
| Key::Right
;
1012 return modifier
| Key::Left
;
1014 return modifier
| Key::End
;
1016 return modifier
| Key::Home
;
1021 default: // urxvt mouse
1022 m_mouse_event
.x
= 0;
1023 delim
= parse_number(m_mouse_event
.x
);
1026 m_mouse_event
.y
= 0;
1027 delim
= parse_number(m_mouse_event
.y
);
1032 return define_mouse_event(key
);
1043 default: // alt + something
1045 auto key_prim
= getInputChar(key
);
1046 if (key_prim
!= Key::None
)
1047 return Key::Alt
| key_prim
;
1053 Key::Type
Window::readKey()
1056 // if there are characters in input queue,
1057 // get them and return immediately.
1058 if (!m_input_queue
.empty())
1060 result
= m_input_queue
.front();
1061 m_input_queue
.pop();
1067 FD_SET(STDIN_FILENO
, &fdset
);
1068 timeval timeout
= { m_window_timeout
/1000, (m_window_timeout
%1000)*1000 };
1070 int fd_max
= STDIN_FILENO
;
1071 for (FDCallbacks::const_iterator it
= m_fds
.begin(); it
!= m_fds
.end(); ++it
)
1073 if (it
->first
> fd_max
)
1075 FD_SET(it
->first
, &fdset
);
1078 if (select(fd_max
+1, &fdset
, 0, 0, m_window_timeout
< 0 ? 0 : &timeout
) > 0)
1080 if (FD_ISSET(STDIN_FILENO
, &fdset
))
1081 result
= getInputChar(wgetch(m_window
));
1085 for (FDCallbacks::const_iterator it
= m_fds
.begin(); it
!= m_fds
.end(); ++it
)
1086 if (FD_ISSET(it
->first
, &fdset
))
1094 void Window::pushChar(const Key::Type ch
)
1096 m_input_queue
.push(ch
);
1099 std::string
Window::prompt(const std::string
&base
, size_t width
, bool encrypted
)
1103 rl::aborted
= false;
1105 getyx(m_window
, rl::start_y
, rl::start_x
);
1106 rl::width
= std::min(m_width
-rl::start_x
-1, width
-1);
1107 rl::encrypted
= encrypted
;
1108 rl::base
= base
.c_str();
1112 m_escape_terminal_sequences
= false;
1113 char *input
= readline(nullptr);
1114 m_escape_terminal_sequences
= true;
1117 if (input
!= nullptr)
1119 #ifdef HAVE_READLINE_HISTORY_H
1120 if (!encrypted
&& input
[0] != 0)
1122 #endif // HAVE_READLINE_HISTORY_H
1128 throw PromptAborted(std::move(result
));
1133 void Window::goToXY(int x
, int y
)
1135 wmove(m_window
, y
, x
);
1140 return getcurx(m_window
);
1145 return getcury(m_window
);
1148 bool Window::hasCoords(int &x
, int &y
)
1150 return wmouse_trafo(m_window
, &y
, &x
, 0);
1153 bool Window::runPromptHook(const char *arg
, bool *done
) const
1157 bool continue_
= m_prompt_hook(arg
);
1158 if (done
!= nullptr)
1166 size_t Window::getWidth() const
1174 size_t Window::getHeight() const
1176 size_t height
= m_height
;
1179 if (!m_title
.empty())
1184 size_t Window::getStartX() const
1192 size_t Window::getStarty() const
1194 size_t starty
= m_start_y
;
1197 if (!m_title
.empty())
1202 const std::string
&Window::getTitle() const
1207 const Color
&Window::getColor() const
1212 const Border
&Window::getBorder() const
1217 int Window::getTimeout() const
1219 return m_window_timeout
;
1222 const MEVENT
&Window::getMouseEvent()
1224 return m_mouse_event
;
1227 void Window::scroll(Scroll where
)
1230 scrollok(m_window
, 1);
1237 wscrl(m_window
, -1);
1239 case Scroll::PageUp
:
1240 wscrl(m_window
, m_width
);
1242 case Scroll::PageDown
:
1243 wscrl(m_window
, -m_width
);
1249 scrollok(m_window
, 0);
1253 Window
&Window::operator<<(const Color
&c
)
1257 while (!m_color_stack
.empty())
1258 m_color_stack
.pop();
1259 setColor(m_base_color
);
1263 if (!m_color_stack
.empty())
1264 m_color_stack
.pop();
1265 if (!m_color_stack
.empty())
1266 setColor(m_color_stack
.top());
1268 setColor(m_base_color
);
1273 m_color_stack
.push(c
);
1278 Window
&Window::operator<<(Format format
)
1283 bold((m_bold_counter
= 0));
1284 reverse((m_reverse_counter
= 0));
1285 altCharset((m_alt_charset_counter
= 0));
1288 bold(++m_bold_counter
);
1290 case Format::NoBold
:
1291 if (--m_bold_counter
<= 0)
1292 bold((m_bold_counter
= 0));
1294 case Format::Underline
:
1295 underline(++m_underline_counter
);
1297 case Format::NoUnderline
:
1298 if (--m_underline_counter
<= 0)
1299 underline((m_underline_counter
= 0));
1301 case Format::Reverse
:
1302 reverse(++m_reverse_counter
);
1304 case Format::NoReverse
:
1305 if (--m_reverse_counter
<= 0)
1306 reverse((m_reverse_counter
= 0));
1308 case Format::AltCharset
:
1309 altCharset(++m_alt_charset_counter
);
1311 case Format::NoAltCharset
:
1312 if (--m_alt_charset_counter
<= 0)
1313 altCharset((m_alt_charset_counter
= 0));
1319 Window
&Window::operator<<(TermManip tm
)
1323 case TermManip::ClearToEOL
:
1325 auto x
= getX(), y
= getY();
1326 mvwhline(m_window
, y
, x
, ' ', m_width
-x
);
1334 Window
&Window::operator<<(const XY
&coords
)
1336 goToXY(coords
.x
, coords
.y
);
1340 Window
&Window::operator<<(const char *s
)
1342 waddstr(m_window
, s
);
1346 Window
&Window::operator<<(char c
)
1348 // the following causes problems: https://github.com/arybczak/ncmpcpp/issues/21
1349 // waddnstr(m_window, &c, 1);
1350 wprintw(m_window
, "%c", c
);
1354 Window
&Window::operator<<(const wchar_t *ws
)
1356 # ifdef NCMPCPP_UNICODE
1357 waddwstr(m_window
, ws
);
1359 wprintw(m_window
, "%ls", ws
);
1360 # endif // NCMPCPP_UNICODE
1364 Window
&Window::operator<<(wchar_t wc
)
1366 # ifdef NCMPCPP_UNICODE
1367 waddnwstr(m_window
, &wc
, 1);
1369 wprintw(m_window
, "%lc", wc
);
1370 # endif // NCMPCPP_UNICODE
1374 Window
&Window::operator<<(int i
)
1376 wprintw(m_window
, "%d", i
);
1380 Window
&Window::operator<<(double d
)
1382 wprintw(m_window
, "%f", d
);
1386 Window
&Window::operator<<(const std::string
&s
)
1388 waddnstr(m_window
, s
.c_str(), s
.length());
1392 Window
&Window::operator<<(const std::wstring
&ws
)
1394 # ifdef NCMPCPP_UNICODE
1395 waddnwstr(m_window
, ws
.c_str(), ws
.length());
1397 wprintw(m_window
, "%lc", ws
.c_str());
1398 # endif // NCMPCPP_UNICODE
1402 Window
&Window::operator<<(size_t s
)
1404 wprintw(m_window
, "%zu", s
);