/*********************************************************************** * flabel.cpp - Widget FLabel * * * * This file is part of the FINAL CUT widget toolkit * * * * Copyright 2014-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/fapplication.h" #include "final/fcolorpair.h" #include "final/fevent.h" #include "final/flabel.h" #include "final/flog.h" #include "final/fstatusbar.h" namespace finalcut { //---------------------------------------------------------------------- // class FLabel //---------------------------------------------------------------------- // constructors and destructor //---------------------------------------------------------------------- FLabel::FLabel(FWidget* parent) : FWidget{parent} { init(); } //---------------------------------------------------------------------- FLabel::FLabel (const FString& txt, FWidget* parent) : FWidget{parent} , text{txt} { init(); setText(txt); } //---------------------------------------------------------------------- FLabel::~FLabel() // destructor { delAccelerator(); } // FLabel operators //---------------------------------------------------------------------- FLabel& FLabel::operator = (const FString& s) { setText(s); return *this; } //---------------------------------------------------------------------- FLabel& FLabel::operator << (UniChar c) { setText(text + static_cast(c)); return *this; } //---------------------------------------------------------------------- FLabel& FLabel::operator << (const wchar_t c) { setText(text + c); return *this; } //---------------------------------------------------------------------- const FLabel& FLabel::operator >> (FString& s) const { s += text; return *this; } // public methods of FLabel //---------------------------------------------------------------------- void FLabel::setAccelWidget (FWidget* widget) { if ( widget ) accel_widget = widget; accel_widget->addCallback ( "destroy", this, &FLabel::cb_accelWidgetDestroyed ); } //---------------------------------------------------------------------- void FLabel::setAlignment (Align align) { if ( align != Align::Left && align != Align::Center && align != Align::Right ) alignment = Align::Left; else alignment = align; } //---------------------------------------------------------------------- void FLabel::resetColors() { useParentWidgetColor(); const auto& wc = getColorTheme(); emphasis_color = wc->label_emphasis_fg; ellipsis_color = wc->label_ellipsis_fg; } //---------------------------------------------------------------------- bool FLabel::setEnable (bool enable) { FWidget::setEnable(enable); if ( enable ) setHotkeyAccelerator(); else delAccelerator(); return enable; } //---------------------------------------------------------------------- void FLabel::setText (const FString& txt) { text.setString(txt); multiline_text = text.split("\r\n"); if ( int(multiline_text.size()) > 1 ) multiline = true; else multiline = false; if ( isEnabled() ) { delAccelerator(); setHotkeyAccelerator(); } } //---------------------------------------------------------------------- void FLabel::hide() { FWidget::hide(); hideArea (getSize()); } //---------------------------------------------------------------------- void FLabel::onMouseDown (FMouseEvent* ev) { if ( ev->getButton() != MouseButton::Left ) return; if ( ! (isEnabled() && accel_widget) ) { // send click to the parent widget if ( auto parent = getParentWidget() ) { const auto b = ev->getButton(); const auto& tp = ev->getTermPos(); const auto& p = parent->termToWidgetPos(tp); const auto& _ev = \ std::make_shared(Event::MouseDown, p, tp, b); FApplication::sendEvent (parent, _ev.get()); } return; } if ( ! accel_widget->hasFocus() ) { // focus the accelerator widget auto focused_widget = getFocusWidget(); accel_widget->setFocus(); if ( focused_widget ) focused_widget->redraw(); accel_widget->redraw(); if ( getStatusBar() ) accel_widget->getStatusBar()->drawMessage(); } } //---------------------------------------------------------------------- void FLabel::onAccel (FAccelEvent* ev) { if ( ! (isEnabled() && accel_widget) ) return; if ( ! accel_widget->hasFocus() ) { auto focused_widget = ev->focusedWidget(); if ( focused_widget && focused_widget->isWidget() ) { accel_widget->setFocus(); focused_widget->redraw(); accel_widget->redraw(); FFocusEvent in (Event::FocusIn); FApplication::sendEvent(accel_widget, &in); if ( getStatusBar() ) accel_widget->getStatusBar()->drawMessage(); } } ev->accept(); } //---------------------------------------------------------------------- void FLabel::cb_accelWidgetDestroyed() { accel_widget = nullptr; delAccelerator(); } // private methods of FLabel //---------------------------------------------------------------------- void FLabel::init() { unsetFocusable(); resetColors(); } //---------------------------------------------------------------------- void FLabel::setHotkeyAccelerator() { setHotkeyViaString (this, text); } //---------------------------------------------------------------------- std::size_t FLabel::getAlignOffset (const std::size_t length) const { const std::size_t width(getWidth()); if ( alignment == Align::Center ) { if ( length < width ) return (width - length) / 2; } else if ( alignment == Align::Right && length < width ) { return width - length; } return 0; } //---------------------------------------------------------------------- void FLabel::draw() { if ( text.isEmpty() ) return; if ( FTerm::isMonochron() ) { setReverse(true); if ( hasEmphasis() ) setBold(true); } if ( hasEmphasis() ) setColor (emphasis_color, getBackgroundColor()); else setColor(); // Draw the text if ( multiline && getHeight() >= 2 ) drawMultiLine(); else drawSingleLine(); if ( FTerm::isMonochron() ) { setReverse(false); if ( hasEmphasis() ) setBold(false); } } //---------------------------------------------------------------------- void FLabel::drawMultiLine() { std::size_t y{0}; const std::size_t text_lines = multiline_text.size(); bool hotkey_printed{false}; while ( y < text_lines && y < std::size_t(getHeight()) ) { FString label_text{}; hotkeypos = NOT_SET; const auto length = multiline_text[y].getLength(); column_width = getColumnWidth(multiline_text[y]); if ( ! hotkey_printed ) hotkeypos = finalcut::getHotkeyPos (multiline_text[y], label_text); else label_text = multiline_text[y]; print() << FPoint{1, 1 + int(y)}; if ( hotkeypos != NOT_SET ) { align_offset = getAlignOffset(length - 1); hotkey_printed = true; } else align_offset = getAlignOffset(length); printLine (label_text); y++; } } //---------------------------------------------------------------------- void FLabel::drawSingleLine() { FString label_text{}; column_width = getColumnWidth(text); hotkeypos = finalcut::getHotkeyPos (text, label_text); if ( hotkeypos != NOT_SET ) column_width--; print() << FPoint{1, 1}; align_offset = getAlignOffset(column_width); printLine (label_text); } //---------------------------------------------------------------------- void FLabel::printLine (FString& line) { std::size_t to_char{}; std::size_t to_column{}; const std::size_t width(getWidth()); if ( align_offset > 0 ) print (FString{align_offset, ' '}); // leading spaces if ( column_width <= width ) { to_char = line.getLength(); to_column = column_width; } else { to_column = ( width >= 2 ) ? width - 2 : 0; to_char = getLengthFromColumnWidth(line, to_column); } if ( hasReverseMode() ) setReverse(true); for (std::size_t z{0}; z < to_char; z++) { if ( ! std::iswprint(std::wint_t(line[z])) && ! FTerm::isNewFont() && ( line[z] < UniChar::NF_rev_left_arrow2 || line[z] > UniChar::NF_check_mark ) ) { line[z] = L' '; } if ( z == hotkeypos && getFlags().active ) { const auto& wc = getColorTheme(); setColor (wc->label_hotkey_fg, wc->label_hotkey_bg); if ( ! getFlags().no_underline ) setUnderline(); print (line[z]); if ( ! getFlags().no_underline ) unsetUnderline(); if ( hasEmphasis() ) setColor (emphasis_color, getBackgroundColor()); else setColor(); } else print (line[z]); } if ( column_width > width ) { // Print ellipsis print() << FColorPair{ellipsis_color, getBackgroundColor()} << FString{".."}.left(width); setColor(); } else if ( align_offset + to_column < width ) { // Print trailing spaces const std::size_t len = width - align_offset - to_column; print (FString{len, ' '}); } if ( hasReverseMode() ) setReverse(false); } } // namespace finalcut