/*********************************************************************** * foptiattr.cpp - Sets video attributes in optimized order * * * * This file is part of the FINAL CUT widget toolkit * * * * Copyright 2016-2021 Markus Gans * * * * FINAL CUT is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * FINAL CUT is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program. If not, see * * . * ***********************************************************************/ #include #include #include "final/fc.h" #include "final/foptiattr.h" #include "final/fstartoptions.h" #include "final/ftermcap.h" namespace finalcut { //---------------------------------------------------------------------- // class FOptiAttr //---------------------------------------------------------------------- // constructors and destructor //---------------------------------------------------------------------- FOptiAttr::FOptiAttr() { attr_buf.reserve(SGRoptimizer::ATTR_BUF_SIZE); // Set bits that must not be reset reset_byte_mask.attr.bit.transparent = true; reset_byte_mask.attr.bit.color_overlay = true; reset_byte_mask.attr.bit.inherit_background = true; reset_byte_mask.attr.bit.no_changes = true; reset_byte_mask.attr.bit.printed = true; } // public methods of FOptiAttr //---------------------------------------------------------------------- auto FOptiAttr::getInstance() -> FOptiAttr& { static const auto& opti_attr = make_unique(); return *opti_attr; } //---------------------------------------------------------------------- void FOptiAttr::setTermEnvironment (const TermEnv& term_env) { // Set all required termcap values at once // and initialize the FOptiAttr environment set_enter_bold_mode (term_env.t_enter_bold_mode); set_exit_bold_mode (term_env.t_exit_bold_mode); set_enter_dim_mode (term_env.t_enter_dim_mode); set_exit_dim_mode (term_env.t_exit_dim_mode); set_enter_italics_mode (term_env.t_enter_italics_mode); set_exit_italics_mode (term_env.t_exit_italics_mode); set_enter_underline_mode (term_env.t_enter_underline_mode); set_exit_underline_mode (term_env.t_exit_underline_mode); set_enter_blink_mode (term_env.t_enter_blink_mode); set_exit_blink_mode (term_env.t_exit_blink_mode); set_enter_reverse_mode (term_env.t_enter_reverse_mode); set_exit_reverse_mode (term_env.t_exit_reverse_mode); set_enter_standout_mode (term_env.t_enter_standout_mode); set_exit_standout_mode (term_env.t_exit_standout_mode); set_enter_secure_mode (term_env.t_enter_secure_mode); set_exit_secure_mode (term_env.t_exit_secure_mode); set_enter_protected_mode (term_env.t_enter_protected_mode); set_exit_protected_mode (term_env.t_exit_protected_mode); set_enter_crossed_out_mode (term_env.t_enter_crossed_out_mode); set_exit_crossed_out_mode (term_env.t_exit_crossed_out_mode); set_enter_dbl_underline_mode (term_env.t_enter_dbl_underline_mode); set_exit_dbl_underline_mode (term_env.t_exit_dbl_underline_mode); set_set_attributes (term_env.t_set_attributes); set_exit_attribute_mode (term_env.t_exit_attribute_mode); set_enter_alt_charset_mode (term_env.t_enter_alt_charset_mode); set_exit_alt_charset_mode (term_env.t_exit_alt_charset_mode); set_enter_pc_charset_mode (term_env.t_enter_pc_charset_mode); set_exit_pc_charset_mode (term_env.t_exit_pc_charset_mode); set_a_foreground_color (term_env.t_set_a_foreground); set_a_background_color (term_env.t_set_a_background); set_foreground_color (term_env.t_set_foreground); set_background_color (term_env.t_set_background); set_term_color_pair (term_env.t_set_color_pair); set_orig_pair (term_env.t_orig_pair); set_orig_orig_colors (term_env.t_orig_colors); max_color = term_env.max_color; attr_without_color = term_env.attr_without_color; ansi_default_color = term_env.ansi_default_color; initialize(); } //---------------------------------------------------------------------- void FOptiAttr::set_enter_bold_mode (const char cap[]) { if ( cap ) { F_enter_bold_mode.cap = cap; F_enter_bold_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_bold_mode (const char cap[]) { if ( cap ) { F_exit_bold_mode.cap = cap; F_exit_bold_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_dim_mode (const char cap[]) { if ( cap ) { F_enter_dim_mode.cap = cap; F_enter_dim_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_dim_mode (const char cap[]) { if ( cap ) { F_exit_dim_mode.cap = cap; F_exit_dim_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_italics_mode (const char cap[]) { if ( cap ) { F_enter_italics_mode.cap = cap; F_enter_italics_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_italics_mode (const char cap[]) { if ( cap ) { F_exit_italics_mode.cap = cap; F_exit_italics_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_underline_mode (const char cap[]) { if ( cap ) { F_enter_underline_mode.cap = cap; F_enter_underline_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_underline_mode (const char cap[]) { if ( cap ) { F_exit_underline_mode.cap = cap; F_exit_underline_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_blink_mode (const char cap[]) { if ( cap ) { F_enter_blink_mode.cap = cap; F_enter_blink_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_blink_mode (const char cap[]) { if ( cap ) { F_exit_blink_mode.cap = cap; F_exit_blink_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_reverse_mode (const char cap[]) { if ( cap ) { F_enter_reverse_mode.cap = cap; F_enter_reverse_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_reverse_mode (const char cap[]) { if ( cap ) { F_exit_reverse_mode.cap = cap; F_exit_reverse_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_secure_mode (const char cap[]) { if ( cap ) { F_enter_secure_mode.cap = cap; F_enter_secure_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_secure_mode (const char cap[]) { if ( cap ) { F_exit_secure_mode.cap = cap; F_exit_secure_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_protected_mode (const char cap[]) { if ( cap ) { F_enter_protected_mode.cap = cap; F_enter_protected_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_protected_mode (const char cap[]) { if ( cap ) { F_exit_protected_mode.cap = cap; F_exit_protected_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_crossed_out_mode (const char cap[]) { if ( cap ) { F_enter_crossed_out_mode.cap = cap; F_enter_crossed_out_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_crossed_out_mode (const char cap[]) { if ( cap ) { F_exit_crossed_out_mode.cap = cap; F_exit_crossed_out_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_dbl_underline_mode (const char cap[]) { if ( cap ) { F_enter_dbl_underline_mode.cap = cap; F_enter_dbl_underline_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_dbl_underline_mode (const char cap[]) { if ( cap ) { F_exit_dbl_underline_mode.cap = cap; F_exit_dbl_underline_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_standout_mode (const char cap[]) { if ( cap ) { F_enter_standout_mode.cap = cap; F_enter_standout_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_standout_mode (const char cap[]) { if ( cap ) { F_exit_standout_mode.cap = cap; F_exit_standout_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_set_attributes (const char cap[]) { if ( cap ) { F_set_attributes.cap = cap; F_set_attributes.caused_reset = true; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_attribute_mode (const char cap[]) { if ( cap ) { F_exit_attribute_mode.cap = cap; F_exit_attribute_mode.caused_reset = true; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_alt_charset_mode (const char cap[]) { if ( cap ) { F_enter_alt_charset_mode.cap = cap; F_enter_alt_charset_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_alt_charset_mode (const char cap[]) { if ( cap ) { F_exit_alt_charset_mode.cap = cap; F_exit_alt_charset_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_enter_pc_charset_mode (const char cap[]) { if ( cap ) { F_enter_pc_charset_mode.cap = cap; F_enter_pc_charset_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_exit_pc_charset_mode (const char cap[]) { if ( cap ) { F_exit_pc_charset_mode.cap = cap; F_exit_pc_charset_mode.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_a_foreground_color (const char cap[]) { if ( cap ) { F_set_a_foreground.cap = cap; F_set_a_foreground.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_a_background_color (const char cap[]) { if ( cap ) { F_set_a_background.cap = cap; F_set_a_background.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_foreground_color (const char cap[]) { if ( cap ) { F_set_foreground.cap = cap; F_set_foreground.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_background_color (const char cap[]) { if ( cap ) { F_set_background.cap = cap; F_set_background.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_term_color_pair (const char cap[]) { if ( cap ) { F_set_color_pair.cap = cap; F_set_color_pair.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_orig_pair (const char cap[]) { if ( cap ) { F_orig_pair.cap = cap; F_orig_pair.caused_reset = false; } } //---------------------------------------------------------------------- void FOptiAttr::set_orig_orig_colors (const char cap[]) { if ( cap ) { F_orig_colors.cap = cap; F_orig_colors.caused_reset = false; } } //---------------------------------------------------------------------- bool FOptiAttr::isNormal (const FChar& ch) { return hasNoAttribute(ch) && ! hasColor(ch); } //---------------------------------------------------------------------- void FOptiAttr::initialize() { if ( max_color < 8 ) monochron = true; else monochron = false; if ( caused_reset_attributes(F_exit_bold_mode.cap) ) F_exit_bold_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_dim_mode.cap) ) F_exit_dim_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_italics_mode.cap) ) F_exit_italics_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_blink_mode.cap) ) F_exit_blink_mode.caused_reset = true; if ( caused_reset_attributes ( F_exit_underline_mode.cap , all_tests & ~same_like_ue) ) F_exit_underline_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_reverse_mode.cap) ) F_exit_reverse_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_secure_mode.cap) ) F_exit_secure_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_protected_mode.cap) ) F_exit_protected_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_crossed_out_mode.cap) ) F_exit_crossed_out_mode.caused_reset = true; if ( caused_reset_attributes(F_exit_dbl_underline_mode.cap) ) F_exit_dbl_underline_mode.caused_reset = true; if ( caused_reset_attributes ( F_exit_standout_mode.cap , all_tests & ~same_like_se) ) F_exit_standout_mode.caused_reset = true; if ( hasCharsetEquivalence() ) alt_equal_pc_charset = true; } //---------------------------------------------------------------------- FColor FOptiAttr::vga2ansi (FColor color) { // VGA | ANSI // i R G B | i B G R //---------+--------- // 0 0 0 0 | 0 0 0 0 i = intensity bit // 0 0 0 1 | 0 1 0 0 R = red // 0 0 1 0 | 0 0 1 0 G = green // 0 0 1 1 | 0 1 1 0 B = blue // 0 1 0 0 | 0 0 0 1 // 0 1 0 1 | 0 1 0 1 // 0 1 1 0 | 0 0 1 1 // 0 1 1 1 | 0 1 1 1 // 1 0 0 0 | 1 0 0 0 // 1 0 0 1 | 1 1 0 0 // 1 0 1 0 | 1 0 1 0 // 1 0 1 1 | 1 1 1 0 // 1 1 0 0 | 1 0 0 1 // 1 1 0 1 | 1 1 0 1 // 1 1 1 0 | 1 0 1 1 // 1 1 1 1 | 1 1 1 1 if ( color == FColor::Default ) color = FColor::Black; else if ( color < 16 ) { constexpr std::array lookup_table = {{ FColor(0), FColor(4), FColor(2), FColor(6), FColor(1), FColor(5), FColor(3), FColor(7), FColor(8), FColor(12), FColor(10), FColor(14), FColor(9), FColor(13), FColor(11), FColor(15) }}; color = lookup_table[uInt16(color)]; } return color; } //---------------------------------------------------------------------- std::string FOptiAttr::changeAttribute (FChar& term, FChar& next) { const bool next_has_color = hasColor(next); fake_reverse = false; attr_buf.clear(); prevent_no_color_video_attributes (term, next_has_color); prevent_no_color_video_attributes (next); detectSwitchOn (term, next); detectSwitchOff (term, next); // Simulate invisible characters if ( ! F_enter_secure_mode.cap && next.attr.bit.invisible ) next.encoded_char[0] = ' '; // Look for no changes if ( ! (switchOn() || switchOff() || hasColorChanged(term, next)) ) return {}; if ( hasNoAttribute(next) ) { deactivateAttributes (term, next); } else if ( F_set_attributes.cap && (! term.attr.bit.pc_charset || alt_equal_pc_charset) ) { changeAttributeSGR (term, next); } else { changeAttributeSeparately (term, next); } if ( FStartOptions::getInstance().sgr_optimizer ) sgr_optimizer.optimize(); return attr_buf; } // private methods of FOptiAttr //---------------------------------------------------------------------- inline bool FOptiAttr::setTermBold (FChar& term) { term.attr.bit.bold = true; if ( append_sequence(F_enter_bold_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermBold (FChar& term) { // Back to normal intensity (turns off bold + dim) if ( F_exit_bold_mode.caused_reset ) reset(term); else { term.attr.bit.bold = false; term.attr.bit.dim = false; } if ( append_sequence(F_exit_bold_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermDim (FChar& term) { term.attr.bit.dim = true; if ( append_sequence(F_enter_dim_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermDim (FChar& term) { // Back to normal intensity (turns off bold + dim) if ( F_exit_dim_mode.caused_reset ) reset(term); else { term.attr.bit.bold = false; term.attr.bit.dim = false; } if ( append_sequence(F_exit_dim_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermItalic (FChar& term) { term.attr.bit.italic = true; if ( append_sequence(F_enter_italics_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermItalic (FChar& term) { if ( F_exit_italics_mode.caused_reset ) reset(term); else term.attr.bit.italic = false; if ( append_sequence(F_exit_italics_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermUnderline (FChar& term) { term.attr.bit.underline = true; if ( append_sequence(F_enter_underline_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermUnderline (FChar& term) { // Turns off every underlining if ( F_exit_underline_mode.caused_reset ) reset(term); else { term.attr.bit.underline = false; term.attr.bit.dbl_underline = false; } if ( append_sequence(F_exit_underline_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermBlink (FChar& term) { term.attr.bit.blink = true; if ( append_sequence(F_enter_blink_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermBlink (FChar& term) { if ( F_exit_blink_mode.caused_reset ) reset(term); else term.attr.bit.blink = false; if ( append_sequence(F_exit_blink_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermReverse (FChar& term) { term.attr.bit.reverse = true; if ( ! fake_reverse && append_sequence(F_enter_reverse_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermReverse (FChar& term) { if ( F_exit_reverse_mode.caused_reset ) reset(term); else term.attr.bit.reverse = false; if ( ! fake_reverse && append_sequence(F_exit_reverse_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermStandout (FChar& term) { term.attr.bit.standout = true; if ( ! fake_reverse && append_sequence(F_enter_standout_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermStandout (FChar& term) { if ( F_exit_standout_mode.caused_reset ) reset(term); else term.attr.bit.standout = false; if ( ! fake_reverse && append_sequence(F_exit_standout_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermInvisible (FChar& term) { term.attr.bit.invisible = true; if ( append_sequence(F_enter_secure_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermInvisible (FChar& term) { if ( F_exit_secure_mode.caused_reset ) reset(term); else term.attr.bit.invisible = false; if ( append_sequence(F_exit_secure_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermProtected (FChar& term) { term.attr.bit.protect = true; if ( append_sequence(F_enter_protected_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermProtected (FChar& term) { if ( F_exit_protected_mode.caused_reset ) reset(term); else term.attr.bit.protect = false; if ( append_sequence(F_exit_protected_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermCrossedOut (FChar& term) { term.attr.bit.crossed_out = true; if ( append_sequence(F_enter_crossed_out_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermCrossedOut (FChar& term) { if ( F_exit_crossed_out_mode.caused_reset ) reset(term); else term.attr.bit.crossed_out = false; if ( append_sequence(F_exit_crossed_out_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermDoubleUnderline (FChar& term) { term.attr.bit.dbl_underline = true; if ( append_sequence(F_enter_dbl_underline_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermDoubleUnderline (FChar& term) { // Turns off every underlining if ( F_exit_dbl_underline_mode.caused_reset ) reset(term); else { term.attr.bit.underline = false; term.attr.bit.dbl_underline = false; } if ( append_sequence(F_exit_dbl_underline_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- bool FOptiAttr::setTermAttributes (FChar& term, const TCapAttributes& attr) { if ( F_set_attributes.cap ) { const auto sgr = FTermcap::encodeParameter ( F_set_attributes.cap , attr.p1 && ! fake_reverse , attr.p2 , attr.p3 && ! fake_reverse , attr.p4 , attr.p5 , attr.p6 , attr.p7 , attr.p8 , attr.p9 ); append_sequence (sgr.data()); resetColor(term); term.attr.bit.standout = attr.p1; term.attr.bit.underline = attr.p2; term.attr.bit.reverse = attr.p3; term.attr.bit.blink = attr.p4; term.attr.bit.dim = attr.p5; term.attr.bit.bold = attr.p6; term.attr.bit.invisible = attr.p7; term.attr.bit.protect = attr.p8; term.attr.bit.alt_charset = attr.p9; term.attr.bit.pc_charset = false; term.attr.bit.italic = false; term.attr.bit.crossed_out = false; term.attr.bit.dbl_underline = false; return true; } else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermAttributes (FChar& term) { reset(term); if ( append_sequence(F_exit_attribute_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermAltCharset (FChar& term) { term.attr.bit.alt_charset = true; if ( alt_equal_pc_charset && term.attr.bit.pc_charset ) return false; if ( append_sequence(F_enter_alt_charset_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermAltCharset (FChar& term) { term.attr.bit.alt_charset = false; if ( alt_equal_pc_charset && term.attr.bit.pc_charset ) return false; if ( append_sequence(F_exit_alt_charset_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::setTermPCcharset (FChar& term) { term.attr.bit.pc_charset = true; if ( alt_equal_pc_charset && term.attr.bit.alt_charset ) return false; if ( append_sequence(F_enter_pc_charset_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::unsetTermPCcharset (FChar& term) { term.attr.bit.pc_charset = false; if ( alt_equal_pc_charset && term.attr.bit.alt_charset ) return false; if ( append_sequence(F_exit_pc_charset_mode.cap) ) return true; else return false; } //---------------------------------------------------------------------- bool FOptiAttr::setTermDefaultColor (FChar& term) { term.fg_color = FColor::Default; term.bg_color = FColor::Default; if ( append_sequence(F_orig_pair.cap) ) return true; else if ( append_sequence(F_orig_colors.cap) ) return true; else if ( ansi_default_color ) { std::string sgr_39_49{CSI "39;49m"}; append_sequence (sgr_39_49.c_str()); return true; } else return false; } //---------------------------------------------------------------------- void FOptiAttr::setAttributesOn (FChar& term) { if ( on.attr.bit.alt_charset ) setTermAltCharset(term); if ( on.attr.bit.pc_charset ) setTermPCcharset(term); if ( on.attr.bit.bold ) setTermBold(term); if ( on.attr.bit.dim ) setTermDim(term); if ( on.attr.bit.italic ) setTermItalic(term); if ( on.attr.bit.underline ) setTermUnderline(term); if ( on.attr.bit.blink ) setTermBlink(term); if ( on.attr.bit.reverse ) setTermReverse(term); if ( on.attr.bit.standout ) setTermStandout(term); if ( on.attr.bit.invisible ) setTermInvisible(term); if ( on.attr.bit.protect ) setTermProtected(term); if ( on.attr.bit.crossed_out ) setTermCrossedOut(term); if ( on.attr.bit.dbl_underline ) setTermDoubleUnderline(term); } //---------------------------------------------------------------------- void FOptiAttr::setAttributesOff (FChar& term) { if ( off.attr.bit.pc_charset ) unsetTermPCcharset(term); if ( off.attr.bit.alt_charset ) unsetTermAltCharset(term); if ( off.attr.bit.bold ) unsetTermBold(term); if ( off.attr.bit.dim ) unsetTermDim(term); if ( off.attr.bit.italic ) unsetTermItalic(term); if ( off.attr.bit.underline ) unsetTermUnderline(term); if ( off.attr.bit.blink ) unsetTermBlink(term); if ( off.attr.bit.reverse ) unsetTermReverse(term); if ( off.attr.bit.standout ) unsetTermStandout(term); if ( off.attr.bit.invisible ) unsetTermInvisible(term); if ( off.attr.bit.protect ) unsetTermProtected(term); if ( off.attr.bit.crossed_out ) unsetTermCrossedOut(term); if ( off.attr.bit.dbl_underline ) unsetTermDoubleUnderline(term); } //---------------------------------------------------------------------- bool FOptiAttr::hasColor (const FChar& attr) { if ( attr.fg_color == FColor::Default && attr.bg_color == FColor::Default ) return false; else return true; } //---------------------------------------------------------------------- bool FOptiAttr::hasAttribute (const FChar& attr) { return attr.attr.bit.bold || attr.attr.bit.dim || attr.attr.bit.italic || attr.attr.bit.underline || attr.attr.bit.blink || attr.attr.bit.reverse || attr.attr.bit.standout || attr.attr.bit.invisible || attr.attr.bit.protect || attr.attr.bit.crossed_out || attr.attr.bit.dbl_underline || attr.attr.bit.alt_charset || attr.attr.bit.pc_charset; } //---------------------------------------------------------------------- bool FOptiAttr::hasNoAttribute (const FChar& attr) { return ! hasAttribute(attr); } //---------------------------------------------------------------------- inline bool FOptiAttr::hasColorChanged ( const FChar& term , const FChar& next ) const { bool frev { ( on.attr.bit.reverse || on.attr.bit.standout || off.attr.bit.reverse || off.attr.bit.standout ) && fake_reverse }; return frev || term.fg_color != next.fg_color || term.bg_color != next.bg_color; } //---------------------------------------------------------------------- inline void FOptiAttr::resetColor (FChar& attr) const { attr.fg_color = FColor::Default; attr.bg_color = FColor::Default; } //---------------------------------------------------------------------- inline void FOptiAttr::prevent_no_color_video_attributes ( FChar& attr , bool next_has_color ) { // Ignore attributes which can not combined with a color if ( ! (hasColor(attr) || next_has_color) || attr_without_color <= 0 ) return; for (auto bit{1}; bit < no_mode; bit <<= 1) { switch ( bit & attr_without_color ) { case standout_mode: attr.attr.bit.standout = false; break; case underline_mode: attr.attr.bit.underline = false; break; case reverse_mode: fake_reverse = true; break; case blink_mode: attr.attr.bit.blink = false; break; case dim_mode: attr.attr.bit.dim = false; break; case bold_mode: attr.attr.bit.bold = false; break; case invisible_mode: attr.attr.bit.invisible = false; break; case protected_mode: attr.attr.bit.protect = false; break; case alt_charset_mode: attr.attr.bit.alt_charset = false; break; case italic_mode: attr.attr.bit.italic = false; break; default: break; } } } //---------------------------------------------------------------------- inline void FOptiAttr::deactivateAttributes (FChar& term, FChar& next) { if ( hasAttribute(term) ) { if ( F_exit_attribute_mode.cap ) { if ( off.attr.bit.alt_charset ) // Required for rxvt terminals unsetTermAltCharset(term); unsetTermAttributes(term); if ( off.attr.bit.pc_charset ) unsetTermPCcharset(term); } else setAttributesOff(term); } if ( hasColorChanged(term, next) ) change_color (term, next); } //---------------------------------------------------------------------- inline void FOptiAttr::changeAttributeSGR (FChar& term, FChar& next) { bool pc_charset_usable{true}; if ( switchOn() || switchOff() ) setTermAttributes ( term , { next.attr.bit.standout , next.attr.bit.underline , next.attr.bit.reverse , next.attr.bit.blink , next.attr.bit.dim , next.attr.bit.bold , next.attr.bit.invisible , next.attr.bit.protect , next.attr.bit.alt_charset } ); if ( alt_equal_pc_charset && F_enter_pc_charset_mode.cap && next.attr.bit.alt_charset ) { term.attr.bit.pc_charset = next.attr.bit.pc_charset; off.attr.bit.pc_charset = false; pc_charset_usable = false; } if ( off.attr.bit.pc_charset ) unsetTermPCcharset(term); if ( ! term.attr.bit.italic && next.attr.bit.italic ) setTermItalic(term); if ( ! term.attr.bit.crossed_out && next.attr.bit.crossed_out ) setTermCrossedOut(term); if ( ! term.attr.bit.dbl_underline && next.attr.bit.dbl_underline ) setTermDoubleUnderline(term); if ( ! term.attr.bit.pc_charset && next.attr.bit.pc_charset && pc_charset_usable ) setTermPCcharset(term); if ( hasColorChanged(term, next) ) change_color(term, next); } //---------------------------------------------------------------------- inline void FOptiAttr::changeAttributeSeparately (FChar& term, FChar& next) { setAttributesOff(term); if ( hasColorChanged(term, next) ) change_color (term, next); detectSwitchOn (term, next); // After reset all attributes setAttributesOn(term); } //---------------------------------------------------------------------- void FOptiAttr::change_color (FChar& term, FChar& next) { if ( monochron ) { next.fg_color = FColor::Default; next.bg_color = FColor::Default; return; } if ( next.fg_color != FColor::Default ) next.fg_color %= uInt16(max_color); if ( next.bg_color != FColor::Default ) next.bg_color %= uInt16(max_color); FColor fg = next.fg_color; FColor bg = next.bg_color; if ( fg == FColor::Default || bg == FColor::Default ) change_to_default_color (term, next, fg, bg); if ( fake_reverse && fg == FColor::Default && bg == FColor::Default ) return; if ( fake_reverse && (next.attr.bit.reverse || next.attr.bit.standout) ) { std::swap (fg, bg); if ( fg == FColor::Default || bg == FColor::Default ) setTermDefaultColor(term); } change_current_color (term, fg, bg); term.fg_color = next.fg_color; term.bg_color = next.bg_color; } //---------------------------------------------------------------------- inline void FOptiAttr::change_to_default_color ( FChar& term, FChar& next , FColor& fg, FColor& bg ) { if ( ansi_default_color ) { if ( fg == FColor::Default && term.fg_color != FColor::Default && bg == FColor::Default && term.bg_color != FColor::Default ) { setTermDefaultColor(term); } else if ( fg == FColor::Default && term.fg_color != FColor::Default ) { std::string sgr_39{CSI "39m"}; append_sequence (sgr_39.c_str()); term.fg_color = FColor::Default; } else if ( bg == FColor::Default && term.bg_color != FColor::Default ) { const char* sgr_49; const auto& op = F_orig_pair.cap; if ( op && std::strncmp (op, CSI "39;49;25m", 11) == 0 ) sgr_49 = CSI "49;25m"; else sgr_49 = CSI "49m"; append_sequence (sgr_49); term.bg_color = FColor::Default; } } else if ( ! setTermDefaultColor(term) ) { // Fallback to gray on black fg = next.fg_color = FColor::LightGray; bg = next.bg_color = FColor::Black; } } //---------------------------------------------------------------------- inline void FOptiAttr::change_current_color ( const FChar& term , FColor fg, FColor bg ) { const auto& AF = F_set_a_foreground.cap; const auto& AB = F_set_a_background.cap; const auto& Sf = F_set_foreground.cap; const auto& Sb = F_set_background.cap; const auto& sp = F_set_color_pair.cap; const bool frev ( ( off.attr.bit.reverse || off.attr.bit.standout || term.attr.bit.reverse || term.attr.bit.standout ) && fake_reverse ); if ( AF && AB ) { const auto ansi_fg = vga2ansi(fg); const auto ansi_bg = vga2ansi(bg); if ( term.fg_color != fg || frev ) { const auto& color_str = FTermcap::encodeParameter(AF, uInt16(ansi_fg)); append_sequence (color_str.data()); } if ( term.bg_color != bg || frev ) { const auto& color_str = FTermcap::encodeParameter(AB, uInt16(ansi_bg)); append_sequence (color_str.data()); } } else if ( Sf && Sb ) { if ( term.fg_color != fg || frev ) { const auto& color_str = FTermcap::encodeParameter(Sf, uInt16(fg)); append_sequence (color_str.data()); } if ( term.bg_color != bg || frev ) { const auto& color_str = FTermcap::encodeParameter(Sb, uInt16(bg)); append_sequence (color_str.data()); } } else if ( sp ) { fg = vga2ansi(fg); bg = vga2ansi(bg); const auto& color_str = FTermcap::encodeParameter(sp, uInt16(fg), uInt16(bg)); append_sequence (color_str.data()); } } //---------------------------------------------------------------------- inline void FOptiAttr::resetAttribute (FChar& attr) const { attr.attr.byte[0] = 0; attr.attr.byte[1] &= reset_byte_mask.attr.byte[1]; } //---------------------------------------------------------------------- inline void FOptiAttr::reset (FChar& attr) const { resetAttribute(attr); resetColor(attr); } //---------------------------------------------------------------------- bool FOptiAttr::caused_reset_attributes (const char cap[], uChar test) const { // test if "cap" reset all attributes if ( cap ) { const auto& ue = F_exit_underline_mode.cap; const auto& se = F_exit_standout_mode.cap; const auto& me = F_exit_attribute_mode.cap; if ( (test & test_ansi_reset) && std::strncmp (cap, CSI "m", 3) == 0 ) return true; if ( (test & test_adm3_reset) && std::strncmp (cap, ESC "G0", 3) == 0 ) return true; if ( (test & same_like_ue) && ue && std::strcmp (cap, ue) == 0 && std::strncmp (cap, CSI "24m", 5) != 0) return true; if ( (test & same_like_se) && se && std::strcmp (cap, se) == 0 && std::strncmp (cap, CSI "27m", 5) != 0 ) return true; if ( (test & same_like_me) && me && std::strcmp (cap, me) == 0 ) return true; } return false; } //---------------------------------------------------------------------- inline bool FOptiAttr::hasCharsetEquivalence() const { // Detect if alt charset and pc charset are the same sequences const auto& alt_on = F_enter_alt_charset_mode.cap; const auto& alt_off = F_enter_pc_charset_mode.cap; const auto& pc_on = F_enter_pc_charset_mode.cap; const auto& pc_off = F_exit_pc_charset_mode.cap; if ( alt_on && pc_on && std::strcmp (alt_on, pc_on) == 0 ) return true; if ( alt_off && pc_off && std::strcmp (alt_off, pc_off) == 0 ) return true; return false; } //---------------------------------------------------------------------- inline void FOptiAttr::detectSwitchOn (const FChar& term, const FChar& next) { on.attr.bit.bold = ! term.attr.bit.bold && next.attr.bit.bold; on.attr.bit.dim = ! term.attr.bit.dim && next.attr.bit.dim; on.attr.bit.italic = ! term.attr.bit.italic && next.attr.bit.italic; on.attr.bit.underline = ! term.attr.bit.underline && next.attr.bit.underline; on.attr.bit.blink = ! term.attr.bit.blink && next.attr.bit.blink; on.attr.bit.reverse = ! term.attr.bit.reverse && next.attr.bit.reverse; on.attr.bit.standout = ! term.attr.bit.standout && next.attr.bit.standout; on.attr.bit.invisible = ! term.attr.bit.invisible && next.attr.bit.invisible; on.attr.bit.protect = ! term.attr.bit.protect && next.attr.bit.protect; on.attr.bit.crossed_out = ! term.attr.bit.crossed_out && next.attr.bit.crossed_out; on.attr.bit.dbl_underline = ! term.attr.bit.dbl_underline && next.attr.bit.dbl_underline; on.attr.bit.alt_charset = ! term.attr.bit.alt_charset && next.attr.bit.alt_charset; on.attr.bit.pc_charset = ! term.attr.bit.pc_charset && next.attr.bit.pc_charset; } //---------------------------------------------------------------------- inline void FOptiAttr::detectSwitchOff (const FChar& term, const FChar& next) { off.attr.bit.bold = term.attr.bit.bold && ! next.attr.bit.bold; off.attr.bit.dim = term.attr.bit.dim && ! next.attr.bit.dim; off.attr.bit.italic = term.attr.bit.italic && ! next.attr.bit.italic; off.attr.bit.underline = term.attr.bit.underline && ! next.attr.bit.underline; off.attr.bit.blink = term.attr.bit.blink && ! next.attr.bit.blink; off.attr.bit.reverse = term.attr.bit.reverse && ! next.attr.bit.reverse; off.attr.bit.standout = term.attr.bit.standout && ! next.attr.bit.standout; off.attr.bit.invisible = term.attr.bit.invisible && ! next.attr.bit.invisible; off.attr.bit.protect = term.attr.bit.protect && ! next.attr.bit.protect; off.attr.bit.crossed_out = term.attr.bit.crossed_out && ! next.attr.bit.crossed_out; off.attr.bit.dbl_underline = term.attr.bit.dbl_underline && ! next.attr.bit.dbl_underline; off.attr.bit.alt_charset = term.attr.bit.alt_charset && ! next.attr.bit.alt_charset; off.attr.bit.pc_charset = term.attr.bit.pc_charset && ! next.attr.bit.pc_charset; } //---------------------------------------------------------------------- inline bool FOptiAttr::switchOn() const { return hasAttribute(on); } //---------------------------------------------------------------------- inline bool FOptiAttr::switchOff() const { return hasAttribute(off); } //---------------------------------------------------------------------- inline bool FOptiAttr::append_sequence (const char seq[]) { if ( ! seq ) return false; attr_buf.append(seq); return true; } } // namespace finalcut