diff --git a/.gitignore b/.gitignore index 02e5572c..c1e67a39 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ examples/windows examples/term-attributes examples/transparent examples/input-dialog +examples/fullwidth-character examples/7segment examples/choice examples/listbox diff --git a/ChangeLog b/ChangeLog index 12a017ff..857ac33f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2019-09-28 Markus Gans + * Support for displaying full-width characters (2 columns wide) + on the terminal. This is particularly important for the correct + display of CJK characters + +2019-09-16 Markus Gans + * Improve FStartOptions implementation + 2019-09-08 Markus Gans * Remove the lines of the #pragma pack() directive from the code because they caused a misaligned address diff --git a/README.md b/README.md index 88bd0194..b9b1b04f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,12 @@ ![FINAL CUT](logo/svg/finalcut-logo.svg) ============================================ -### Building and code analysis +# Library for creating terminal applications with text-based widgets +The FINAL CUT is a C++ class library and widget toolkit with full mouse support for creating a [text-based user interface](https://en.wikipedia.org/wiki/Text-based_user_interface). The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple text windows on the screen. + +The structure of the Qt framework was originally the inspiration for the C++ class design of FINAL CUT. It provides common controls like dialog boxes, push buttons, check boxes, radio buttons, input lines, list boxes, status bars and so on. + +## Building and code analysis *Latest release:*
     [![Latest Release](https://img.shields.io/github/release/gansm/finalcut.svg)](https://github.com/gansm/finalcut/releases)
*License:*
@@ -15,12 +20,7 @@ *Class Reference:*
     [![documented](https://codedocs.xyz/gansm/finalcut.svg)](https://codedocs.xyz/gansm/finalcut/hierarchy.html) -### Description -The FINAL CUT is a C++ class library and widget toolkit with full mouse support for creating a [text-based user interface](https://en.wikipedia.org/wiki/Text-based_user_interface). The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple text windows on the screen. - -The structure of the Qt framework was originally the inspiration for the C++ class design of FINAL CUT. It provides common controls like dialog boxes, push buttons, check boxes, radio buttons, input lines, list boxes, status bars and so on. - -### Installation +## Installation ```bash > git clone git://github.com/gansm/finalcut.git > cd finalcut @@ -30,7 +30,7 @@ The structure of the Qt framework was originally the inspiration for the C++ cla > su -c "make install" ``` -### Supported platforms +## Supported platforms * Linux * FreeBSD * NetBSD @@ -39,13 +39,12 @@ The structure of the Qt framework was originally the inspiration for the C++ cla * Cygwin * Solaris -### First steps +## First steps +Read here [how to use the library](doc/first-steps.md#first-steps-with-the-final-cut-widget-toolkit) -[How to use the library](doc/first-steps.md#first-steps-with-the-final-cut-widget-toolkit) +## Some screenshots -### Screenshots - -The FFileDialog widget: +The FFileDialog widget with incremental file name search: ![FFileDialog](doc/fileopen-dialog.png) diff --git a/build.sh b/build.sh index 72d5b5f9..6a6d69fd 100755 --- a/build.sh +++ b/build.sh @@ -59,7 +59,7 @@ case "$1" in ;; "--fulldebug"|"fulldebug") - if ! ./configure --prefix="$PREFIX" CPPFLAGS="-DDEBUG" CXXFLAGS="-g -O0 -DDEBUG -W -Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -fstack-protector -Wstrict-aliasing -Wstrict-aliasing=3 -Wswitch -Wswitch-enum -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvolatile-register-var -Wwrite-strings -Wsign-promo -Woverloaded-virtual -Wstrict-null-sentinel -fext-numeric-literals -Wreorder -Wnoexcept -Wnarrowing -Wliteral-suffix -Wctor-dtor-privacy -ftree-loop-distribute-patterns -Wmemset-transposed-args" + if ! ./configure --prefix="$PREFIX" CPPFLAGS="-DDEBUG" CXXFLAGS="-g -O0 -DDEBUG -W -Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -fstack-protector -Wstrict-aliasing -Wstrict-aliasing=3 -Wswitch -Wswitch-enum -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvolatile-register-var -Wwrite-strings -Wsign-promo -Woverloaded-virtual -Wstrict-null-sentinel -fext-numeric-literals -Wreorder -Wnoexcept -Wnarrowing -Wliteral-suffix -Wctor-dtor-privacy -ftree-loop-distribute-patterns -Wmemset-transposed-args -Wno-format-nonliteral" then echo "${RED}Configure failed!${NORMAL}" 1>&2 exit 255 diff --git a/debian/libfinal-dev.docs b/debian/libfinal-dev.docs index 3cd9709d..9a1eb31e 100644 --- a/debian/libfinal-dev.docs +++ b/debian/libfinal-dev.docs @@ -1,8 +1,20 @@ +AUTHORS +COPYING +COPYING.LESSER +ChangeLog +README.md doc/calendar-draft.png +doc/calculator.png doc/class-diagram.txt +doc/class_template.cpp +doc/class_template.h doc/console_codes-manual.sh doc/console_ioctl-manual.sh +doc/faq.md doc/fileopen-dialog.png +doc/first-steps.md +doc/framebuffer.txt +doc/Mandelbrot.png doc/ncurses.supp doc/newfont1.png doc/newfont2.png @@ -13,6 +25,8 @@ doc/terminfo-capabilities.sh doc/terminfo-manual.sh doc/textview.png doc/TODO +doc/vga.txt doc/vt100_line_drawing_graphics.png doc/virtual-terminal.txt +doc/xterm.txt doc/xgraphics diff --git a/doc/Makefile.am b/doc/Makefile.am index 5843c239..2eebc1d2 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -6,12 +6,17 @@ docdir = ${datadir}/doc/${PACKAGE} EXTRA_DIST = \ calendar-draft.png \ + calculator.png \ class-diagram.txt \ + class_template.cpp \ + class_template.h \ console_codes-manual.sh \ console_ioctl-manual.sh \ faq.md \ fileopen-dialog.png \ first-steps.md \ + framebuffer.txt \ + Mandelbrot.png \ ncurses.supp \ newfont1.png \ newfont2.png \ @@ -22,18 +27,25 @@ EXTRA_DIST = \ terminfo-manual.sh \ textview.png \ TODO \ + vga.txt \ vt100_line_drawing_graphics.png \ virtual-terminal.txt \ + xterm.txt \ xgraphics doc_DATA = \ calendar-draft.png \ + calculator.png \ class-diagram.txt \ + class_template.cpp \ + class_template.h \ console_codes-manual.sh \ console_ioctl-manual.sh \ faq.md \ fileopen-dialog.png \ first-steps.md \ + framebuffer.txt \ + Mandelbrot.png \ ncurses.supp \ newfont1.png \ newfont2.png \ @@ -44,6 +56,8 @@ doc_DATA = \ terminfo-manual.sh \ textview.png \ TODO \ + vga.txt \ vt100_line_drawing_graphics.png \ virtual-terminal.txt \ + xterm.txt \ xgraphics diff --git a/examples/Makefile.am b/examples/Makefile.am index 73a0df1c..2722af3b 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -11,6 +11,7 @@ noinst_PROGRAMS = \ hello \ dialog \ input-dialog \ + fullwidth-character \ 7segment \ choice \ listbox \ @@ -36,6 +37,7 @@ noinst_PROGRAMS = \ hello_SOURCES = hello.cpp dialog_SOURCES = dialog.cpp input_dialog_SOURCES = input-dialog.cpp +fullwidth_character_SOURCES = fullwidth-character.cpp 7segment_SOURCES = 7segment.cpp choice_SOURCES = choice.cpp listbox_SOURCES = listbox.cpp diff --git a/examples/checklist.cpp b/examples/checklist.cpp index 89665f5d..3dff90c1 100644 --- a/examples/checklist.cpp +++ b/examples/checklist.cpp @@ -73,14 +73,14 @@ CheckList::CheckList (finalcut::FWidget* parent) { setText (L"Shopping list"); setShadow(); - setGeometry ( FPoint(int(1 + (parent->getWidth() - 30) / 2), 5) - , FSize(30, 13) ); + setGeometry ( FPoint(int(1 + (parent->getWidth() - 28) / 2), 5) + , FSize(28, 13) ); listView.ignorePadding(); listView.setGeometry (FPoint(1, 2), FSize(getWidth(), getHeight() - 1)); // Add columns to the view listView.addColumn ("Item"); - listView.addColumn ("Priority", 12); + listView.addColumn ("Priority", 9); // Set the type of sorting listView.setColumnSortType (1, fc::by_name); diff --git a/examples/fullwidth-character.cpp b/examples/fullwidth-character.cpp new file mode 100644 index 00000000..7b379d64 --- /dev/null +++ b/examples/fullwidth-character.cpp @@ -0,0 +1,137 @@ +/*********************************************************************** +* fullwidth-letter.cpp - Demonstrates use of full-width characters * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2019 Markus Gans * +* * +* The 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. * +* * +* The 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 + +#define full(...) finalcut::getFullWidth(__VA_ARGS__) + +using finalcut::FPoint; +using finalcut::FSize; + + +//---------------------------------------------------------------------- +// main part +//---------------------------------------------------------------------- +int main (int argc, char* argv[]) +{ + // Create the application object + finalcut::FApplication app(argc, argv); + + // Create a simple dialog box + finalcut::FDialog dgl(&app); + dgl.setText (full("Dialog")); + dgl.setSize (FSize(37, 16)); + dgl.setPos (FPoint( int(app.getDesktopWidth() - dgl.getWidth()) / 2 + , int(app.getDesktopHeight() - dgl.getHeight()) / 2)); + dgl.setShadow(); + + // Create input fields + finalcut::FLineEdit field1 (&dgl); + field1.setLabelText (full("Input")); + field1.setText (L"你好"); // Nǐ hǎo (chinese) + field1.setStatusbarMessage (full("Type your text here")); + field1.setGeometry (FPoint(15, 1), FSize(19, 1)); + + finalcut::FLineEdit field2 (&dgl); + field2.setLabelText (L"Comment"); + field2.setText (full(L"Hello")); + field2.setStatusbarMessage (full("Post a comment")); + field2.setGeometry (FPoint(15, 3), FSize(19, 1)); + + // Create the button group + finalcut::FButtonGroup group (full("Side"), &dgl); + group.setGeometry(FPoint(2, 5), FSize(32, 3)); + + // Create radio buttons + finalcut::FRadioButton left ("&" + full("Left"), &group); + finalcut::FRadioButton right ("&" + full("Right"), &group); + left.setStatusbarMessage (full("Prefer the left side")); + right.setStatusbarMessage (full("Prefer the right side")); + left.setGeometry (FPoint(1, 1), FSize(8, 1)); + right.setGeometry (FPoint(15, 1), FSize(10, 1)); + + // Create a scrollable text field + finalcut::FTextView scroll_text (&dgl); + scroll_text.setGeometry (FPoint(2, 8), FSize(32, 3)); + finalcut::FString text_line{"FINAL CUT supports " + "full-width characters."}; + scroll_text.setStatusbarMessage ("You can scroll right and " + "left with the arrow keys"); + scroll_text.append(full(text_line)); + + // Create a OK button + finalcut::FButton btn("&OK", &dgl); + btn.setStatusbarMessage (full("Press Enter to exit the dialog")); + btn.setGeometry (FPoint(24, 12), FSize(10, 1)); + + // Create the status bar + finalcut::FStatusBar sbar(&dgl); + finalcut::FStatusKey key_F1 (finalcut::fc::Fkey_f1, "Info", &sbar); + + // Create the menu bar + finalcut::FMenuBar Menubar(&dgl); + + // Create menu bar items + finalcut::FMenu File{L"&File", &Menubar}; + finalcut::FMenuItem Edit{L"&Edit", &Menubar}; + finalcut::FMenuItem Exit{L"E&xit", &Menubar}; + + // Create file menu items + finalcut::FMenuItem Open{"&Open", &File}; + finalcut::FMenuItem Print{"&Print", &File}; + finalcut::FMenuItem Line{&File}; + Line.setSeparator(); + finalcut::FMenuItem Quit{"&Quit", &File}; + Quit.addAccelerator (finalcut::fc::Fckey_q); // Ctrl + Q + + // Callback lambda expressions + auto cb_exit = \ + [] (finalcut::FWidget*, FDataPtr data) + { + auto a = static_cast(data); + a->quit(); + }; + + auto cb_tooltip = \ + [] (finalcut::FWidget*, FDataPtr data) + { + auto a = static_cast(data); + finalcut::FToolTip tooltip(a); + tooltip.setText (full("A tooltip with\ncharacters\n" + "in full-width\nfor 3 seconds")); + tooltip.show(); + sleep(3); + }; + + // Connect the signals with the callback lambda expressions + btn.addCallback ("clicked", cb_exit, &app); + Exit.addCallback ("clicked", cb_exit, &app); + Quit.addCallback ("clicked", cb_exit, &app); + key_F1.addCallback ("activate",cb_tooltip, &app); + + // Set dialog object as main widget + app.setMainWidget(&dgl); + + // Show and start the application + dgl.show(); + return app.exec(); +} diff --git a/examples/input-dialog.cpp b/examples/input-dialog.cpp index 05b0950a..b8cbf360 100644 --- a/examples/input-dialog.cpp +++ b/examples/input-dialog.cpp @@ -1,5 +1,5 @@ /*********************************************************************** -* input-dialog.cpp - an input field example * +* input-dialog.cpp - An input field example * * * * This file is part of the Final Cut widget toolkit * * * diff --git a/examples/mandelbrot.cpp b/examples/mandelbrot.cpp index da6afb08..cf2454fb 100644 --- a/examples/mandelbrot.cpp +++ b/examples/mandelbrot.cpp @@ -76,7 +76,7 @@ void Mandelbrot::draw() int xoffset{2}; int yoffset{2}; int current_line{0}; - int Cols = int(getClientWidth()); + int Cols = int(getClientWidth()); int Lines = int(getClientHeight()); double dX = (x_max - x_min) / (Cols - 1); diff --git a/examples/mouse.cpp b/examples/mouse.cpp index 04ea5137..77e504fb 100644 --- a/examples/mouse.cpp +++ b/examples/mouse.cpp @@ -457,7 +457,7 @@ void MouseDraw::draw() //---------------------------------------------------------------------- void MouseDraw::drawBrush (int x, int y, bool swap_color) { - int Cols = int(getWidth()); + int Cols = int(getWidth()); int Lines = int(getHeight()); if ( x > 10 && x < Cols && y > 2 && y < Lines ) diff --git a/examples/opti-move.cpp b/examples/opti-move.cpp index 0b1e3263..54c0316f 100644 --- a/examples/opti-move.cpp +++ b/examples/opti-move.cpp @@ -108,7 +108,7 @@ void move (int xold, int yold, int xnew, int ynew) << " "; // get the move string char* buffer = finalcut::FTerm::moveCursorString (xold, yold, xnew, ynew); - uInt len = uInt(std::strlen(buffer)); + uInt len = uInt(std::strlen(buffer)); for (uInt i = 0; i < len; i++) { diff --git a/examples/scrollview.cpp b/examples/scrollview.cpp index 015b7f5f..7480446a 100644 --- a/examples/scrollview.cpp +++ b/examples/scrollview.cpp @@ -118,8 +118,8 @@ Scrollview::~Scrollview() void Scrollview::setScrollSize (const FSize& size) { FScrollView::setScrollSize (size); - auto width = int(size.getWidth()); - auto height = int(size.getHeight()); + int width = int(size.getWidth()); + int height = int(size.getHeight()); go_south.setPos (FPoint(width - 5, 1)); go_west.setPos (FPoint(width - 5, height - 1)); go_north.setPos (FPoint(1, height - 1)); @@ -141,6 +141,7 @@ void Scrollview::draw() for (int x{0}; x < int(getScrollWidth()); x++) print (32 + ((x + y) % 0x5f)); + } if ( isMonochron() ) diff --git a/examples/string-operations.cpp b/examples/string-operations.cpp index 8b0d695d..04521419 100644 --- a/examples/string-operations.cpp +++ b/examples/string-operations.cpp @@ -643,7 +643,7 @@ void iteratorExample() { // Test: character access with std::iterator const finalcut::FString stringIterator{"iterator"}; - finalcut::FString::iterator iter; + finalcut::FString::const_iterator iter; iter = stringIterator.begin(); std::cout << " " << stringIterator << ": "; diff --git a/examples/ui.cpp b/examples/ui.cpp index 66320e87..f42ac6ab 100644 --- a/examples/ui.cpp +++ b/examples/ui.cpp @@ -1,5 +1,5 @@ /*********************************************************************** -* 7segment.cpp - Seven-segment display example * +* ui.cpp - Example of a user interface * * * * This file is part of the Final Cut widget toolkit * * * @@ -556,6 +556,7 @@ void MyDialog::initWidgets() // A multiple selection listbox myList.setGeometry(FPoint(38, 1), FSize(14, 17)); myList.setText ("Items"); + myList.setStatusbarMessage ("99 items in a list"); myList.setMultiSelection(); myList.reserve(100); @@ -737,7 +738,7 @@ void MyDialog::adjustSize() { auto h = getParentWidget()->getHeight() - 4; setHeight (h, false); - auto X = int((getDesktopWidth() - getWidth()) / 2); + int X = int((getDesktopWidth() - getWidth()) / 2); if ( X < 1 ) X = 1; diff --git a/examples/windows.cpp b/examples/windows.cpp index c83c9ef6..57dea275 100644 --- a/examples/windows.cpp +++ b/examples/windows.cpp @@ -342,12 +342,12 @@ void Window::activateWindow (finalcut::FDialog* win) //---------------------------------------------------------------------- void Window::adjustSize() { - std::size_t w = getDesktopWidth(); - std::size_t h = getDesktopHeight(); - int X = int(1 + (w - 40) / 2) - , Y = int(1 + (h - 22) / 2) - , dx = ( w > 80 ) ? int(w - 80) / 2 : 0 - , dy = ( h > 24 ) ? int(h - 24) / 2 : 0; + std::size_t w = getDesktopWidth(); + std::size_t h = getDesktopHeight(); + int X = int(1 + (w - 40) / 2); + int Y = int(1 + (h - 22) / 2); + int dx = ( w > 80 ) ? int(w - 80) / 2 : 0; + int dy = ( h > 24 ) ? int(h - 24) / 2 : 0; if ( Y < 2 ) Y = 2; @@ -360,9 +360,9 @@ void Window::adjustSize() { if ( (*iter)->is_open ) { - int n = int(std::distance(first, iter)) - , x = dx + 5 + (n % 3) * 25 + int(n / 3) * 3 - , y = dy + 11 + int(n / 3) * 3; + int n = int(std::distance(first, iter)); + int x = dx + 5 + (n % 3) * 25 + int(n / 3) * 3; + int y = dy + 11 + int(n / 3) * 3; (*iter)->dgl->setPos (FPoint(x, y)); } diff --git a/src/Makefile.am b/src/Makefile.am index 0c71d77b..3b093366 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,7 @@ libfinal_la_SOURCES = \ fkey_map.cpp \ fcharmap.cpp \ ftextview.cpp \ + fstartoptions.cpp \ fstatusbar.cpp \ ftermcap.cpp \ ftermcapquirks.cpp \ @@ -114,6 +115,7 @@ finalcutinclude_HEADERS = \ include/final/frect.h \ include/final/fscrollbar.h \ include/final/fscrollview.h \ + include/final/fstartoptions.h \ include/final/fstatusbar.h \ include/final/fstring.h \ include/final/fsystem.h \ diff --git a/src/Makefile.clang b/src/Makefile.clang index 2ecf20f3..65aecbbd 100644 --- a/src/Makefile.clang +++ b/src/Makefile.clang @@ -48,6 +48,7 @@ INCLUDE_HEADERS = \ fmouse.h \ fkeyboard.h \ ftermcap.h \ + fstartoptions.h \ fterm.h \ ftermdata.h \ ftermdebugdata.h \ @@ -114,6 +115,7 @@ OBJS = \ fsystem.o \ fsystemimpl.o \ fkeyboard.o \ + fstartoptions.o \ ftermcap.o \ fterm.o \ ftermdebugdata.o \ @@ -159,7 +161,10 @@ all: dep $(OBJS) $(LIB): all debug: - $(MAKE) $(MAKEFILE) DEBUG="-g -D DEBUG -Wall -Wextra -Wpedantic -Weverything -Wno-padded -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-implicit-fallthrough -Wno-reserved-id-macro" + $(MAKE) $(MAKEFILE) DEBUG="-g -D DEBUG -Wall -Wextra -Wpedantic -Weverything -Wno-padded -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-implicit-fallthrough -Wno-reserved-id-macro -Wno-format-nonliteral" + +unittest: + $(MAKE) $(MAKEFILE) DEBUG="-g -D DEBUG -DUNIT_TEST -Wall -Wextra -Wpedantic -Weverything -Wno-padded -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-implicit-fallthrough -Wno-reserved-id-macro -Wno-format-nonliteral" profile: $(MAKE) $(MAKEFILE) PROFILE="-pg" diff --git a/src/Makefile.gcc b/src/Makefile.gcc index 6fe5de03..c2e1f16b 100644 --- a/src/Makefile.gcc +++ b/src/Makefile.gcc @@ -47,6 +47,7 @@ INCLUDE_HEADERS = \ fsystemimpl.h \ fmouse.h \ fkeyboard.h \ + fstartoptions.h \ ftermcap.h \ fterm.h \ ftermdata.h \ @@ -115,6 +116,7 @@ OBJS = \ fsystemimpl.o \ fkeyboard.o \ ftermcap.o \ + fstartoptions.o \ fterm.o \ ftermdebugdata.o \ ftermios.o \ @@ -160,6 +162,9 @@ $(LIB): all debug: $(MAKE) $(MAKEFILE) DEBUG="-g -D DEBUG -Wall -Wextra -Wpedantic" +unittest: + $(MAKE) $(MAKEFILE) DEBUG="-g -D DEBUG -DUNIT_TEST -Wall -Wextra -Wpedantic" + profile: $(MAKE) $(MAKEFILE) PROFILE="-pg" diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 316a044f..fe496998 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -489,6 +489,12 @@ void FApplication::cmd_options (const int& argc, char* argv[]) } } +//---------------------------------------------------------------------- +inline FStartOptions& FApplication::getStartOptions() +{ + return FStartOptions::getFStartOptions(); +} + //---------------------------------------------------------------------- inline void FApplication::findKeyboardWidget() { diff --git a/src/fbutton.cpp b/src/fbutton.cpp index 8529e40d..782f29f6 100644 --- a/src/fbutton.cpp +++ b/src/fbutton.cpp @@ -238,7 +238,7 @@ void FButton::hide() } else { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); fg = wc.dialog_fg; bg = wc.dialog_bg; } @@ -410,7 +410,7 @@ void FButton::onFocusOut (FFocusEvent*) //---------------------------------------------------------------------- void FButton::init() { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.button_active_fg); setBackgroundColor (wc.button_active_bg); setShadow(); @@ -424,6 +424,9 @@ void FButton::setHotkeyAccelerator() { FKey hotkey = getHotkey(text); + if ( hotkey > 0xff00 && hotkey < 0xff5f ) // full-width character + hotkey -= 0xfee0; + if ( hotkey ) { if ( std::isalpha(int(hotkey)) || std::isdigit(int(hotkey)) ) @@ -466,9 +469,9 @@ inline std::size_t FButton::clickAnimationIndent (FWidget* parent_widget) setColor ( parent_widget->getForegroundColor() , parent_widget->getBackgroundColor() ); - for (std::size_t y{1}; y <= getHeight(); y++) + for (int y{1}; y <= int(getHeight()); y++) { - print() << FPoint(1, int(y)) << ' '; // clear one left █ + print() << FPoint(1, y) << ' '; // clear one left █ } return 1; @@ -563,10 +566,10 @@ inline void FButton::drawButtonTextLine (wchar_t button_text[]) print() << FPoint(2 + int(indent), 1 + int(vcenter_offset)) << FColorPair (button_fg, button_bg); - if ( getWidth() < txtlength + 1 ) + if ( getWidth() < column_width + 1 ) center_offset = 0; else - center_offset = (getWidth() - txtlength - 1) / 2; + center_offset = (getWidth() - column_width - 1) / 2; // Print button text line for (pos = 0; pos < center_offset; pos++) @@ -585,9 +588,9 @@ inline void FButton::drawButtonTextLine (wchar_t button_text[]) if ( active_focus && (isMonochron() || getMaxColor() < 16) ) setBold(); - for ( std::size_t z{0} - ; pos < center_offset + txtlength && z + 2 < getWidth() - ; z++, pos++) + for ( std::size_t z{0}, columns{0} + ; pos < center_offset + column_width && columns + 2 < getWidth() + ; z++) { if ( z == hotkeypos && getFlags().active ) { @@ -613,9 +616,13 @@ inline void FButton::drawButtonTextLine (wchar_t button_text[]) { print (button_text[z]); } + + auto char_width = getColumnWidth (button_text[z]); + columns += char_width; + pos += char_width; } - if ( txtlength + 1 >= getWidth() ) + if ( column_width + 1 >= getWidth() ) { // Print ellipsis print() << FPoint(int(getWidth() + indent) - 2, 1) << ".."; @@ -624,7 +631,7 @@ inline void FButton::drawButtonTextLine (wchar_t button_text[]) if ( active_focus && (isMonochron() || getMaxColor() < 16) ) unsetBold(); - for (pos = center_offset + txtlength; pos < getWidth() - 2; pos++) + for (pos = center_offset + column_width; pos < getWidth() - 2; pos++) print (space_char); // █ } @@ -633,7 +640,8 @@ void FButton::draw() { wchar_t* button_text{}; auto parent_widget = getParentWidget(); - txtlength = text.getLength(); + auto txtlength = text.getLength(); + column_width = getColumnWidth(text); space_char = int(' '); active_focus = getFlags().active && getFlags().focus; @@ -668,7 +676,7 @@ void FButton::draw() hotkeypos = finalcut::getHotkeyPos(text.wc_str(), button_text, uInt(txtlength)); if ( hotkeypos != NOT_SET ) - txtlength--; + column_width--; if ( getHeight() >= 2 ) vcenter_offset = (getHeight() - 1) / 2; diff --git a/src/fbuttongroup.cpp b/src/fbuttongroup.cpp index 48afcb0e..575dfc0e 100644 --- a/src/fbuttongroup.cpp +++ b/src/fbuttongroup.cpp @@ -23,6 +23,7 @@ #include "final/fapplication.h" #include "final/fbuttongroup.h" +#include "final/fcolorpair.h" #include "final/fevent.h" #include "final/fsize.h" #include "final/fstatusbar.h" @@ -142,17 +143,12 @@ bool FButtonGroup::hasFocusedButton() const if ( buttonlist.empty() ) return false; - auto iter = buttonlist.begin(); - auto last = buttonlist.end(); - - while ( iter != last ) + for (auto&& item : buttonlist) { - auto toggle_button = static_cast(*iter); + auto toggle_button = static_cast(item); if ( toggle_button->hasFocus() ) return true; - - ++iter; } return false; @@ -164,17 +160,12 @@ bool FButtonGroup::hasCheckedButton() const if ( buttonlist.empty() ) return false; - auto iter = buttonlist.begin(); - auto last = buttonlist.end(); - - while ( iter != last ) + for (auto&& item : buttonlist) { - auto toggle_button = static_cast(*iter); + auto toggle_button = static_cast(item); if ( toggle_button->isChecked() ) return true; - - ++iter; } return false; @@ -189,14 +180,10 @@ void FButtonGroup::hide() if ( ! buttonlist.empty() ) { - auto iter = buttonlist.begin(); - auto last = buttonlist.end(); - - while ( iter != last ) + for (auto&& item : buttonlist) { - auto toggle_button = static_cast(*iter); + auto toggle_button = static_cast(item); toggle_button->hide(); - ++iter; } } @@ -207,7 +194,7 @@ void FButtonGroup::hide() } else { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); fg = wc.dialog_fg; bg = wc.dialog_bg; } @@ -323,13 +310,11 @@ void FButtonGroup::onFocusIn (FFocusEvent* in_ev) { if ( hasCheckedButton() && ! buttonlist.empty() ) { - auto iter = buttonlist.begin(); - auto last = buttonlist.end(); in_ev->ignore(); - while ( iter != last ) + for (auto&& item : buttonlist) { - auto toggle_button = static_cast(*iter); + auto toggle_button = static_cast(item); if ( toggle_button->isChecked() ) { @@ -356,9 +341,7 @@ void FButtonGroup::onFocusIn (FFocusEvent* in_ev) break; } - - ++iter; - } + } // end of range-based for loop } if ( ! in_ev->isAccepted() ) @@ -393,6 +376,9 @@ void FButtonGroup::setHotkeyAccelerator() { FKey hotkey = getHotkey(text); + if ( hotkey > 0xff00 && hotkey < 0xff5f ) // full-width character + hotkey -= 0xfee0; + if ( hotkey ) { if ( std::isalpha(int(hotkey)) || std::isdigit(int(hotkey)) ) @@ -478,10 +464,10 @@ bool FButtonGroup::isRadioButton (const FToggleButton* button) const //---------------------------------------------------------------------- void FButtonGroup::init() { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.label_fg); setBackgroundColor (wc.label_bg); - setMinimumSize (FSize(7, 4)); + setMinimumSize (FSize(7, 3)); buttonlist.clear(); // no buttons yet } @@ -490,11 +476,21 @@ void FButtonGroup::drawText ( wchar_t LabelText[] , std::size_t hotkeypos , std::size_t length ) { + const auto& wc = getFWidgetColors(); + std::size_t column_width = getColumnWidth(LabelText); + bool ellipsis{false}; + + if ( column_width > getClientWidth() ) + { + std::size_t len = getClientWidth() - 3; + FString s = finalcut::getColumnSubString (LabelText, 1, len); + length = s.getLength(); + ellipsis = true; + } + if ( isMonochron() ) setReverse(true); - const FWidgetColors& wc = getFWidgetColors(); - if ( isEnabled() ) setColor(wc.label_emphasis_fg, wc.label_bg); else @@ -520,6 +516,9 @@ void FButtonGroup::drawText ( wchar_t LabelText[] print (LabelText[z]); } + if ( ellipsis ) // Print ellipsis + print() << FColorPair (wc.label_ellipsis_fg, wc.label_bg) << ".."; + if ( isMonochron() ) setReverse(true); } @@ -533,12 +532,9 @@ void FButtonGroup::directFocus() if ( hasCheckedButton() && ! buttonlist.empty() ) { - auto iter = buttonlist.begin(); - auto last = buttonlist.end(); - - while ( iter != last ) + for (auto&& item : buttonlist) { - auto toggle_button = static_cast(*iter); + auto toggle_button = static_cast(item); if ( toggle_button->isChecked() ) { @@ -559,9 +555,7 @@ void FButtonGroup::directFocus() break; } - - ++iter; - } + } // end of range-based for loop } if ( ! found_checked ) @@ -598,12 +592,9 @@ void FButtonGroup::cb_buttonToggled (FWidget* widget, FDataPtr) if ( buttonlist.empty() ) return; - auto iter = buttonlist.begin(); - auto last = buttonlist.end(); - - while ( iter != last ) + for (auto&& item : buttonlist) { - auto toggle_button = static_cast(*iter); + auto toggle_button = static_cast(item); if ( toggle_button != button && toggle_button->isChecked() @@ -614,8 +605,6 @@ void FButtonGroup::cb_buttonToggled (FWidget* widget, FDataPtr) if ( toggle_button->isShown() ) toggle_button->redraw(); } - - ++iter; } } diff --git a/src/fcharmap.cpp b/src/fcharmap.cpp index c3e21e16..c8ae3e22 100644 --- a/src/fcharmap.cpp +++ b/src/fcharmap.cpp @@ -50,6 +50,9 @@ uInt character[][fc::NUM_OF_ENCODINGS] = {0x2193, 'v', 0x19, 'v'}, // ↓ - DownwardsArrow {0x2192, '>', 0x1a, '>'}, // → - RightwardsArrow {0x2190, '<', 0x1b, '<'}, // ← - LeftwardsArrow + {0x203a, '>', 0xaf, '>'}, // › - SingleRightAngleQuotationMark + {0x2039, '<', 0xae, '<'}, // ‹ - SingleLeftAngleQuotationMark + {0x2026, '.', '.', '.'}, // … - HorizontalEllipsis {0x03c0, '{', 0xe3, 'n'}, // π - Pi {0x207F, 'I', 0xfc, ' '}, // ⁿ - SuperscriptLatinSmallLetterN {0x2265, 'z', 0xf2, '>'}, // ≥ - GreaterThanOrEqualTo @@ -464,6 +467,248 @@ wchar_t cp437_to_ucs[][2] = const std::size_t lastCP437Item = \ std::size_t((sizeof(cp437_to_ucs) / sizeof(cp437_to_ucs[0])) - 1); +// Based on http://www.unicode.org/charts/PDF/UFF00.pdf +wchar_t halfWidth_fullWidth[][2] = +{ + // Fullwidth ASCII variants + {0x0020, 0x3000}, // ' ' -> ' ' + {0x0021, 0xff01}, // ! -> ! + {0x0022, 0xff02}, // " -> " + {0x0023, 0xff03}, // # -> # + {0x0024, 0xff04}, // $ -> $ + {0x0025, 0xff05}, // % -> % + {0x0026, 0xff06}, // & -> & + {0x0027, 0xff07}, // ' -> ' + {0x0028, 0xff08}, // ( -> ( + {0x0029, 0xff09}, // ) -> ) + {0x002a, 0xff0a}, // * -> * + {0x002b, 0xff0b}, // + -> + + {0x002c, 0xff0c}, // , -> , + {0x002d, 0xff0d}, // - -> - + {0x002e, 0xff0e}, // . -> . + {0x002f, 0xff0f}, // / -> / + {0x0030, 0xff10}, // 0 -> 0 + {0x0031, 0xff11}, // 1 -> 1 + {0x0032, 0xff12}, // 2 -> 2 + {0x0033, 0xff13}, // 3 -> 3 + {0x0034, 0xff14}, // 4 -> 4 + {0x0035, 0xff15}, // 5 -> 5 + {0x0036, 0xff16}, // 6 -> 6 + {0x0037, 0xff17}, // 7 -> 7 + {0x0038, 0xff18}, // 8 -> 8 + {0x0039, 0xff19}, // 9 -> 9 + {0x003a, 0xff1a}, // : -> : + {0x003b, 0xff1b}, // ; -> ; + {0x003c, 0xff1c}, // < -> < + {0x003d, 0xff1d}, // = -> = + {0x003e, 0xff1e}, // > -> > + {0x003f, 0xff1f}, // ? -> ? + {0x0040, 0xff20}, // @ -> @ + {0x0041, 0xff21}, // A -> A + {0x0042, 0xff22}, // B -> B + {0x0043, 0xff23}, // C -> C + {0x0044, 0xff24}, // D -> D + {0x0045, 0xff25}, // E -> E + {0x0046, 0xff26}, // F -> F + {0x0047, 0xff27}, // G -> G + {0x0048, 0xff28}, // H -> H + {0x0049, 0xff29}, // I -> I + {0x004a, 0xff2a}, // J -> J + {0x004b, 0xff2b}, // K -> K + {0x004c, 0xff2c}, // L -> L + {0x004d, 0xff2d}, // M -> M + {0x004e, 0xff2e}, // N -> N + {0x004f, 0xff2f}, // O -> O + {0x0050, 0xff30}, // P -> P + {0x0051, 0xff31}, // Q -> Q + {0x0052, 0xff32}, // R -> R + {0x0053, 0xff33}, // S -> S + {0x0054, 0xff34}, // T -> T + {0x0055, 0xff35}, // U -> U + {0x0056, 0xff36}, // V -> V + {0x0057, 0xff37}, // W -> W + {0x0058, 0xff38}, // X -> X + {0x0059, 0xff39}, // Y -> Y + {0x005a, 0xff3a}, // Z -> Z + {0x005b, 0xff3b}, // [ -> [ + {0x005c, 0xff3c}, // \ -> \ + {0x005d, 0xff3c}, // ] -> ] + {0x005e, 0xff3e}, // ^ -> ^ + {0x005f, 0xff3f}, // _ -> _ + {0x0060, 0xff40}, // ` -> ` + {0x0061, 0xff41}, // a -> a + {0x0062, 0xff42}, // b -> b + {0x0063, 0xff43}, // c -> c + {0x0064, 0xff44}, // d -> d + {0x0065, 0xff45}, // e -> e + {0x0066, 0xff46}, // f -> f + {0x0067, 0xff47}, // g -> g + {0x0068, 0xff48}, // h -> h + {0x0069, 0xff49}, // i -> i + {0x006a, 0xff4a}, // j -> j + {0x006b, 0xff4b}, // k -> k + {0x006c, 0xff4c}, // l -> l + {0x006d, 0xff4d}, // m -> m + {0x006e, 0xff4e}, // n -> n + {0x006f, 0xff4f}, // o -> o + {0x0070, 0xff50}, // p -> p + {0x0071, 0xff51}, // q -> q + {0x0072, 0xff52}, // r -> r + {0x0073, 0xff53}, // s -> s + {0x0074, 0xff54}, // t -> t + {0x0075, 0xff55}, // u -> u + {0x0076, 0xff56}, // v -> v + {0x0077, 0xff57}, // w -> w + {0x0078, 0xff58}, // x -> x + {0x0079, 0xff59}, // y -> y + {0x007a, 0xff5a}, // z -> z + {0x007b, 0xff5b}, // { -> { + {0x007c, 0xff5c}, // | -> | + {0x007d, 0xff5d}, // } -> } + {0x007e, 0xff5e}, // ~ -> ~ + {0x007e, 0x0301}, // ~ -> 〜 + // Fullwidth brackets + {0xff5f, 0x2e28}, // ⦅ -> ⸨ + {0xff60, 0x2e29}, // ⦆ -> ⸩ + // Halfwidth CJK punctuation + {0xff61, 0x3002}, // 。 -> 。 + {0xff62, 0x300c}, // 「 -> 「 + {0xff63, 0x300d}, // 」 -> 」 + {0xff64, 0x3001}, // 、 -> 、 + // Halfwidth Katakana variants + {0xff65, 0x30fb}, // ・ -> ・ + {0xff66, 0x30f2}, // ヲ -> ヲ + {0xff67, 0x30a1}, // ァ -> ァ + {0xff68, 0x30a3}, // ィ -> ィ + {0xff69, 0x30a5}, // ゥ -> ゥ + {0xff6a, 0x30a7}, // ェ -> ェ + {0xff6b, 0x30a9}, // ォ -> ォ + {0xff6c, 0x30e3}, // ャ -> ャ + {0xff6d, 0x30e5}, // ュ -> ュ + {0xff6e, 0x30e7}, // ョ -> ョ + {0xff6f, 0x30c3}, // ッ -> ッ + {0xff70, 0x30fc}, // ー -> ー + {0xff71, 0x30a2}, // ア -> ア + {0xff72, 0x30a4}, // イ -> イ + {0xff73, 0x30a6}, // ウ -> ウ + {0xff74, 0x30a8}, // エ -> エ + {0xff75, 0x30aa}, // オ -> オ + {0xff76, 0x30ab}, // カ -> カ + {0xff77, 0x30ad}, // キ -> キ + {0xff78, 0x30af}, // ク -> ク + {0xff79, 0x30b1}, // ケ -> ケ + {0xff7a, 0x30b3}, // コ -> コ + {0xff7b, 0x30b5}, // サ -> サ + {0xff7c, 0x30b7}, // シ -> シ + {0xff7d, 0x30b9}, // ス -> ス + {0xff7e, 0x30bb}, // セ -> セ + {0xff7f, 0x30bd}, // ソ -> ソ + {0xff80, 0x30bf}, // タ -> タ + {0xff81, 0x30c1}, // チ -> チ + {0xff82, 0x30c4}, // ツ -> ツ + {0xff83, 0x30c6}, // テ -> テ + {0xff84, 0x30c8}, // ト -> ト + {0xff85, 0x30ca}, // ナ -> ナ + {0xff86, 0x30cb}, // ニ -> ニ + {0xff87, 0x30cc}, // ヌ -> ヌ + {0xff88, 0x30cd}, // ネ -> ネ + {0xff89, 0x30ce}, // ノ -> ノ + {0xff8a, 0x30cf}, // ハ -> ハ + {0xff8b, 0x30d2}, // ヒ -> ヒ + {0xff8c, 0x30d5}, // フ -> フ + {0xff8d, 0x30d8}, // ヘ -> ヘ + {0xff8e, 0x30db}, // ホ -> ホ + {0xff8f, 0x30de}, // マ -> マ + {0xff90, 0x30df}, // ミ -> ミ + {0xff91, 0x30e0}, // ム -> ム + {0xff92, 0x30e1}, // メ -> メ + {0xff93, 0x30e2}, // モ -> モ + {0xff94, 0x30e4}, // ヤ -> ヤ + {0xff95, 0x30e6}, // ユ -> ユ + {0xff96, 0x30e8}, // ヨ -> ヨ + {0xff97, 0x30e9}, // ラ -> ラ + {0xff98, 0x30ea}, // リ -> リ + {0xff99, 0x30eb}, // ル -> ル + {0xff9a, 0x30ec}, // レ -> レ + {0xff9b, 0x30ed}, // ロ -> ロ + {0xff9c, 0x30ef}, // ワ -> ワ + {0xff9d, 0x30f3}, // ン -> ン + {0xff9e, 0x3099}, // ゙ -> ゙ + {0xff9f, 0x309a}, // ゚ -> ゚ + // Halfwidth Hangul variants + {0xffa0, 0x3164}, // ᅠ-> ᅠ + {0xffa1, 0x3131}, // ᄀ -> ㄱ + {0xffa2, 0x3132}, // ᄁ -> ㄲ + {0xffa3, 0x3133}, // ᆪ -> ㄳ + {0xffa4, 0x3134}, // ᄂ -> ㄴ + {0xffa5, 0x3135}, // ᆬ -> ㄵ + {0xffa6, 0x3136}, // ᆭ -> ㄶ + {0xffa7, 0x3137}, // ᄃ -> ㄷ + {0xffa8, 0x3138}, // ᄄ -> ㄸ + {0xffa9, 0x3139}, // ᄅ -> ㄹ + {0xffaa, 0x313a}, // ᆰ -> ㄺ + {0xffab, 0x313b}, // ᆱ -> ㄻ + {0xffac, 0x313c}, // ᆲ -> ㄼ + {0xffad, 0x313d}, // ᆳ -> ㄽ + {0xffae, 0x313e}, // ᆴ -> ㄾ + {0xffaf, 0x313f}, // ᆵ -> ㄿ + {0xffb0, 0x3140}, // ᄚ -> ㅀ + {0xffb1, 0x3141}, // ᄆ -> ㅁ + {0xffb2, 0x3142}, // ᄇ -> ㅂ + {0xffb3, 0x3143}, // ᄈ -> ㅃ + {0xffb4, 0x3144}, // ᄡ -> ㅄ + {0xffb5, 0x3145}, // ᄉ -> ㅅ + {0xffb6, 0x3146}, // ᄊ -> ㅆ + {0xffb7, 0x3147}, // ᄋ -> ㅇ + {0xffb8, 0x3148}, // ᄌ -> ㅈ + {0xffb9, 0x3149}, // ᄍ -> ㅉ + {0xffba, 0x314a}, // ᄎ -> ㅊ + {0xffbb, 0x314b}, // ᄏ -> ㅋ + {0xffbc, 0x314c}, // ᄐ -> ㅌ + {0xffbd, 0x314d}, // ᄑ -> ㅍ + {0xffbe, 0x314e}, // ᄒ -> ㅎ + {0xffc2, 0x314f}, // ᅡ -> ㅏ + {0xffc3, 0x3150}, // ᅢ -> ㅐ + {0xffc4, 0x3151}, // ᅣ -> ㅑ + {0xffc5, 0x3152}, // ᅤ -> ㅒ + {0xffc6, 0x3153}, // ᅥ -> ㅓ + {0xffc7, 0x3154}, // ᅦ -> ㅔ + {0xffca, 0x3155}, // ᅧ -> ㅕ + {0xffcb, 0x3156}, // ᅨ -> ㅖ + {0xffcc, 0x3157}, // ᅩ -> ㅗ + {0xffcd, 0x3158}, // ᅪ -> ㅘ + {0xffce, 0x3159}, // ᅫ -> ㅙ + {0xffcf, 0x315a}, // ᅬ -> ㅚ + {0xffd2, 0x315b}, // ᅭ -> ㅛ + {0xffd3, 0x315c}, // ᅮ -> ㅜ + {0xffd4, 0x315d}, // ᅯ -> ㅝ + {0xffd5, 0x315e}, // ᅰ -> ㅞ + {0xffd6, 0x315f}, // ᅱ -> ㅟ + {0xffd7, 0x3160}, // ᅲ -> ㅠ + {0xffda, 0x3161}, // ᅳ -> ㅡ + {0xffdb, 0x3162}, // ᅴ -> ㅢ + {0xffdc, 0x3163}, // ᅵ -> ㅣ + // Fullwidth symbol variants + {0x00a2, 0xffe0}, // ¢ -> ¢ + {0x00a3, 0xffe1}, // £ -> £ + {0x00ac, 0xffe2}, // ¬ -> ¬ + {0x00af, 0xffe3}, // ¯ ->  ̄ + {0x00a6, 0xffe4}, // ¦ -> ¦ + {0x00a5, 0xffe5}, // ¥ -> ¥ + {0x20a9, 0xffe6}, // ₩ -> ₩ + // Halfwidth symbol variants + {0xffe8, 0x2502}, // │ -> │ + {0xffe9, 0x2190}, // ← -> ← + {0xffea, 0x2191}, // ↑ -> ↑ + {0xffeb, 0x2192}, // → -> → + {0xffec, 0x2193}, // ↓ -> ↓ + {0xffed, 0x25a0}, // ■ -> ■ + {0xffee, 0x25cb} // ○ -> ○ +}; + +const std::size_t lastHalfWidthItem = \ + std::size_t((sizeof(halfWidth_fullWidth) / sizeof(halfWidth_fullWidth[0])) - 1); + } // namespace fc } // namespace finalcut diff --git a/src/fdialog.cpp b/src/fdialog.cpp index 32ccfc3e..cb62f1f1 100644 --- a/src/fdialog.cpp +++ b/src/fdialog.cpp @@ -784,7 +784,7 @@ void FDialog::init() addDialog(this); setActiveWindow(this); setTransparentShadow(); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.dialog_fg); setBackgroundColor (wc.dialog_bg); auto old_focus = FWidget::getFocusWidget(); @@ -908,7 +908,7 @@ void FDialog::drawBorder() if ( (getMoveSizeWidget() == this || ! resize_click_pos.isOrigin() ) && ! isZoomed() ) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.dialog_resize_fg, getBackgroundColor()); } else @@ -971,7 +971,7 @@ void FDialog::drawBarButton() { // Print the title button print() << FPoint(1, 1); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( dialog_menu && dialog_menu->isShown() ) setColor (wc.titlebar_button_focus_fg, wc.titlebar_button_focus_bg); @@ -1024,7 +1024,7 @@ void FDialog::drawZoomButton() if ( ! isResizeable() ) return; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( zoom_button_pressed ) setColor (wc.titlebar_button_focus_fg, wc.titlebar_button_focus_bg); @@ -1093,7 +1093,7 @@ void FDialog::drawTextBar() // Fill with spaces (left of the title) std::size_t center_offset{0}; std::size_t x{1}; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( getMaxColor() < 16 ) setBold(); @@ -1103,9 +1103,9 @@ void FDialog::drawTextBar() else setColor (wc.titlebar_inactive_fg, wc.titlebar_inactive_bg); - std::size_t width = getWidth(); - std::size_t zoom_btn = getZoomButtonWidth(); - std::size_t length = tb_text.getLength(); + auto width = getWidth(); + auto zoom_btn = getZoomButtonWidth(); + auto length = getColumnWidth(tb_text); if ( width > length + MENU_BTN + zoom_btn ) center_offset = (width - length - MENU_BTN - zoom_btn) / 2; diff --git a/src/fdialoglistmenu.cpp b/src/fdialoglistmenu.cpp index 627cbbe0..9c53b49b 100644 --- a/src/fdialoglistmenu.cpp +++ b/src/fdialoglistmenu.cpp @@ -54,8 +54,8 @@ FDialogListMenu::~FDialogListMenu() //---------------------------------------------------------------------- void FDialogListMenu::init() { - auto menuitem = getItem(); - menuitem->dialog_index = true; + auto m_item = getItem(); + m_item->dialog_index = true; } } // namespace finalcut diff --git a/src/ffiledialog.cpp b/src/ffiledialog.cpp index 4d4e265e..3f5d40ea 100644 --- a/src/ffiledialog.cpp +++ b/src/ffiledialog.cpp @@ -701,7 +701,7 @@ int FFileDialog::changeDir (const FString& dirname) filename.setText('/'); else { - auto baseName = basename(C_STR(lastdir.c_str())); + auto baseName = basename(lastdir.c_str()); selectDirectoryEntry (baseName); } } @@ -728,10 +728,16 @@ int FFileDialog::changeDir (const FString& dirname) void FFileDialog::printPath (const FString& txt) { const auto& path = txt; - const uInt max_width = uInt(filebrowser.getWidth()) - 4; + const std::size_t max_width = filebrowser.getWidth() - 4; + std::size_t column_width = getColumnWidth(path); - if ( path.getLength() > max_width ) - filebrowser.setText(".." + path.right(max_width - 2)); + if ( column_width > max_width ) + { + const std::size_t width = max_width - 2; + std::size_t first = column_width + 1 - width; + FString sub_str(getColumnSubString (path, first, width)); + filebrowser.setText(".." + sub_str); + } else filebrowser.setText(path); } diff --git a/src/flabel.cpp b/src/flabel.cpp index 7494dd0b..89cfc522 100644 --- a/src/flabel.cpp +++ b/src/flabel.cpp @@ -183,24 +183,6 @@ void FLabel::setAlignment (fc::text_alignment align) alignment = align; } -//---------------------------------------------------------------------- -bool FLabel::setEmphasis (bool enable) -{ - if ( emphasis != enable ) - emphasis = enable; - - return enable; -} - -//---------------------------------------------------------------------- -bool FLabel::setReverseMode (bool enable) -{ - if ( reverse_mode != enable ) - reverse_mode = enable; - - return enable; -} - //---------------------------------------------------------------------- bool FLabel::setEnable (bool enable) { @@ -342,7 +324,7 @@ void FLabel::init() } else { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.dialog_fg); setBackgroundColor (wc.dialog_bg); } @@ -353,6 +335,9 @@ void FLabel::setHotkeyAccelerator() { FKey hotkey = getHotkey(text); + if ( hotkey > 0xff00 && hotkey < 0xff5f ) // full-width character + hotkey -= 0xfee0; + if ( hotkey ) { if ( std::isalpha(int(hotkey)) || std::isdigit(int(hotkey)) ) @@ -372,7 +357,7 @@ void FLabel::setHotkeyAccelerator() //---------------------------------------------------------------------- std::size_t FLabel::getAlignOffset (std::size_t length) { - std::size_t width = std::size_t(getWidth()); + std::size_t width(getWidth()); switch ( alignment ) { @@ -398,6 +383,9 @@ std::size_t FLabel::getAlignOffset (std::size_t length) //---------------------------------------------------------------------- void FLabel::draw() { + if ( text.isEmpty() ) + return; + if ( isMonochron() ) { setReverse(true); @@ -435,10 +423,11 @@ void FLabel::drawMultiLine() while ( y < text_lines && y < std::size_t(getHeight()) ) { - wchar_t* label_text; + wchar_t* label_text{}; std::size_t hotkeypos{NOT_SET}; std::size_t align_offset{}; - std::size_t length = multiline_text[y].getLength(); + auto length = multiline_text[y].getLength(); + auto column_width = getColumnWidth(multiline_text[y]); try { @@ -463,13 +452,13 @@ void FLabel::drawMultiLine() if ( hotkeypos != NOT_SET ) { align_offset = getAlignOffset(length - 1); - printLine (label_text, length - 1, hotkeypos, align_offset); + printLine (label_text, length - 1, column_width, hotkeypos, align_offset); hotkey_printed = true; } else { align_offset = getAlignOffset(length); - printLine (label_text, length, NOT_SET, align_offset); + printLine (label_text, length, column_width, NOT_SET, align_offset); } y++; @@ -480,9 +469,10 @@ void FLabel::drawMultiLine() //---------------------------------------------------------------------- void FLabel::drawSingleLine() { - wchar_t* label_text; + wchar_t* label_text{}; std::size_t hotkeypos{NOT_SET}; - std::size_t length = text.getLength(); + auto length = text.getLength(); + auto column_width = getColumnWidth(text); try { @@ -497,37 +487,48 @@ void FLabel::drawSingleLine() hotkeypos = finalcut::getHotkeyPos (text.wc_str(), label_text, length); if ( hotkeypos != NOT_SET ) + { length--; + column_width--; + } print() << FPoint(1, 1); - std::size_t align_offset = getAlignOffset(length); - printLine (label_text, length, hotkeypos, align_offset); + auto align_offset = getAlignOffset(column_width); + printLine (label_text, length, column_width, hotkeypos, align_offset); delete[] label_text; } //---------------------------------------------------------------------- void FLabel::printLine ( wchar_t line[] , std::size_t length + , std::size_t column_width , std::size_t hotkeypos , std::size_t align_offset ) { std::size_t to_char{}; - std::size_t width = std::size_t(getWidth()); + std::size_t to_column{}; + std::size_t width(getWidth()); if ( align_offset > 0 ) print (FString(align_offset, ' ')); // leading spaces - if ( length <= width ) + if ( column_width <= width ) + { to_char = length; + to_column = column_width; + } else - to_char = width - 2; + { + to_column = width - 2; + to_char = getColumnWidthToLength(line, to_column); + } if ( hasReverseMode() ) setReverse(true); for (std::size_t z{0}; z < to_char; z++) { - if ( ! std::iswprint(wint_t(line[z])) ) + if ( ! std::iswprint(std::wint_t(line[z])) ) { if ( ! isNewFont() && ( int(line[z]) < fc::NF_rev_left_arrow2 || int(line[z]) > fc::NF_check_mark ) ) @@ -538,7 +539,7 @@ void FLabel::printLine ( wchar_t line[] if ( z == hotkeypos && getFlags().active ) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.label_hotkey_fg, wc.label_hotkey_bg); if ( ! getFlags().no_underline ) @@ -558,16 +559,16 @@ void FLabel::printLine ( wchar_t line[] print (line[z]); } - if ( length > width ) + if ( column_width > width ) { // Print ellipsis print() << FColorPair(ellipsis_color, getBackgroundColor()) << ".."; setColor(); } - else if ( align_offset + to_char < width ) + else if ( align_offset + to_column < width ) { // Print trailing spaces - std::size_t len = width - align_offset - to_char; + std::size_t len = width - align_offset - to_column; print (FString(len, ' ')); } diff --git a/src/flineedit.cpp b/src/flineedit.cpp index 31f42523..1ec15632 100644 --- a/src/flineedit.cpp +++ b/src/flineedit.cpp @@ -168,7 +168,7 @@ const FLineEdit& FLineEdit::operator >> (FString& s) //---------------------------------------------------------------------- bool FLineEdit::setEnable (bool enable) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); FWidget::setEnable(enable); if ( enable ) @@ -196,7 +196,7 @@ bool FLineEdit::setEnable (bool enable) //---------------------------------------------------------------------- bool FLineEdit::setFocus (bool enable) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); FWidget::setFocus(enable); if ( enable ) @@ -263,7 +263,11 @@ void FLineEdit::setText (const FString& txt) else text.setString(""); - keyEnd(); + if ( isShown() ) + { + cursorEnd(); + adjustTextOffset(); + } } //---------------------------------------------------------------------- @@ -274,20 +278,26 @@ void FLineEdit::setMaxLength (std::size_t max) if ( text.getLength() > max_length ) text.setString(text.left(max_length)); - keyEnd(); + if ( isShown() ) + { + cursorEnd(); + adjustTextOffset(); + } } //---------------------------------------------------------------------- void FLineEdit::setCursorPosition (std::size_t pos) { - cursor_pos = pos; + if ( pos == 0 ) + cursor_pos = 1; + else + cursor_pos = pos - 1; if ( cursor_pos > text.getLength() ) - keyEnd(); - else if ( cursor_pos + 1 >= getWidth() ) - text_offset = text.getLength() - getWidth() + 2; - else - text_offset = 0; + cursor_pos = text.getLength(); + + if ( isShown() ) + adjustTextOffset(); } //---------------------------------------------------------------------- @@ -310,8 +320,11 @@ void FLineEdit::setGeometry ( const FPoint& pos, const FSize& size , bool adjust ) { FWidget::setGeometry(pos, size, adjust); - keyEnd(); + + if ( isShown() ) + adjustTextOffset(); } + //---------------------------------------------------------------------- void FLineEdit::hide() { @@ -326,8 +339,9 @@ void FLineEdit::hide() //---------------------------------------------------------------------- void FLineEdit::clear() { - text_offset = 0; cursor_pos = 0; + text_offset = 0; + char_width_offset = 0; text.clear(); } @@ -339,44 +353,44 @@ void FLineEdit::onKeyPress (FKeyEvent* ev) switch ( key ) { case fc::Fkey_left: - keyLeft(); + cursorLeft(); ev->accept(); break; case fc::Fkey_right: - keyRight(); + cursorRight(); ev->accept(); break; case fc::Fkey_home: - keyHome(); + cursorHome(); ev->accept(); break; case fc::Fkey_end: - keyEnd(); + cursorEnd(); ev->accept(); break; case fc::Fkey_dc: // del key - keyDel(); + deleteCurrentCharacter(); ev->accept(); break; case fc::Fkey_erase: case fc::Fkey_backspace: - keyBackspace(); + deletePreviousCharacter(); ev->accept(); break; case fc::Fkey_ic: // insert key - keyInsert(); + switchInsertMode(); ev->accept(); break; case fc::Fkey_return: case fc::Fkey_enter: - keyEnter(); + acceptInput(); ev->accept(); break; @@ -421,15 +435,19 @@ void FLineEdit::onMouseDown (FMouseEvent* ev) int mouse_x = ev->getX(); int mouse_y = ev->getY(); + int xmin = 2 + int(char_width_offset); - if ( mouse_x >= 2 && mouse_x <= int(getWidth()) && mouse_y == 1 ) + if ( mouse_x >= xmin && mouse_x <= int(getWidth()) && mouse_y == 1 ) { std::size_t len = text.getLength(); - cursor_pos = text_offset + std::size_t(mouse_x) - 2; + cursor_pos = clickPosToCursorPos (std::size_t(mouse_x) - 2); if ( cursor_pos >= len ) cursor_pos = len; + if ( mouse_x == int(getWidth()) ) + adjustTextOffset(); + drawInputField(); updateTerminal(); } @@ -458,11 +476,12 @@ void FLineEdit::onMouseMove (FMouseEvent* ev) if ( mouse_x >= 2 && mouse_x <= int(getWidth()) && mouse_y == 1 ) { - cursor_pos = text_offset + std::size_t(mouse_x) - 2; + cursor_pos = clickPosToCursorPos (std::size_t(mouse_x) - 2); if ( cursor_pos >= len ) cursor_pos = len; + adjustTextOffset(); drawInputField(); updateTerminal(); } @@ -487,14 +506,14 @@ void FLineEdit::onMouseMove (FMouseEvent* ev) else if ( mouse_x >= int(getWidth()) ) { // drag right - if ( ! scroll_timer && text_offset <= len - getWidth() + 1 ) + if ( ! scroll_timer && cursor_pos < len ) { scroll_timer = true; addTimer(scroll_repeat); drag_scroll = FLineEdit::scrollRight; } - if ( text_offset == len - getWidth() + 2 ) + if ( cursor_pos == len ) { delOwnTimer(); drag_scroll = FLineEdit::noScroll; @@ -512,7 +531,7 @@ void FLineEdit::onMouseMove (FMouseEvent* ev) //---------------------------------------------------------------------- void FLineEdit::onTimer (FTimerEvent*) { - std::size_t len = text.getLength(); + auto len = text.getLength(); switch ( int(drag_scroll) ) { @@ -534,14 +553,13 @@ void FLineEdit::onTimer (FTimerEvent*) break; case FLineEdit::scrollRight: - if ( len + 2 < getWidth() - || text_offset == len - getWidth() + 2 ) + if ( text_offset == endPosToOffset(len).first ) { drag_scroll = FLineEdit::noScroll; return; } - if ( text_offset <= len - getWidth() + 1 ) + if ( text_offset < endPosToOffset(len).first ) text_offset++; if ( cursor_pos < len ) @@ -553,6 +571,7 @@ void FLineEdit::onTimer (FTimerEvent*) break; } + adjustTextOffset(); drawInputField(); updateTerminal(); } @@ -626,10 +645,10 @@ void FLineEdit::onFocusOut (FFocusEvent*) //---------------------------------------------------------------------- void FLineEdit::adjustLabel() { - std::size_t label_length = label_text.getLength(); + auto label_width = getColumnWidth(label_text); if ( hasHotkey() ) - label_length--; + label_width--; assert ( label_orientation == label_above || label_orientation == label_left ); @@ -638,12 +657,12 @@ void FLineEdit::adjustLabel() { case label_above: label->setGeometry ( FPoint(getX(), getY() - 1) - , FSize(label_length, 1) ); + , FSize(label_width, 1) ); break; case label_left: - label->setGeometry ( FPoint(getX() - int(label_length) - 1, getY()) - , FSize(label_length, 1) ); + label->setGeometry ( FPoint(getX() - int(label_width) - 1, getY()) + , FSize(label_width, 1) ); break; } } @@ -653,6 +672,9 @@ void FLineEdit::adjustSize() { FWidget::adjustSize(); adjustLabel(); + + if ( isShown() ) + adjustTextOffset(); } @@ -660,7 +682,7 @@ void FLineEdit::adjustSize() //---------------------------------------------------------------------- void FLineEdit::init() { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); label->setAccelWidget(this); setVisibleCursor(); setShadow(); @@ -697,6 +719,12 @@ bool FLineEdit::hasHotkey() //---------------------------------------------------------------------- void FLineEdit::draw() { + if ( cursor_pos == NOT_SET ) + cursorEnd(); + + if ( ! isShown() ) + adjustTextOffset(); + drawInputField(); if ( getFlags().focus && getStatusBar() ) @@ -737,12 +765,15 @@ void FLineEdit::drawInputField() if ( isActiveFocus && getMaxColor() < 16 ) setBold(); - FString show_text(text.mid(1 + text_offset, getWidth() - 2)); + auto text_offset_column = getColumnWidth (text, text_offset); + std::size_t start_column = text_offset_column - char_width_offset + 1; + const FString& show_text = \ + getColumnSubString(text, start_column, getWidth() - 2); if ( show_text ) print (show_text); - std::size_t x = show_text.getLength(); + std::size_t x = getColumnWidth(show_text); while ( x + 1 < getWidth() ) { @@ -762,56 +793,174 @@ void FLineEdit::drawInputField() if ( getFlags().shadow ) drawShadow (); - // set the cursor to the first pos. - setCursorPos (FPoint(int(2 + cursor_pos - text_offset), 1)); + // set the cursor to the insert pos. + auto cursor_pos_column = getColumnWidth (text, cursor_pos); + int xpos = int(2 + cursor_pos_column + - text_offset_column + + char_width_offset); + setCursorPos (FPoint(xpos, 1)); } //---------------------------------------------------------------------- -inline void FLineEdit::keyLeft() +inline FLineEdit::offsetPair FLineEdit::endPosToOffset (std::size_t pos) +{ + std::size_t input_width = getWidth() - 2; + std::size_t fullwidth_char_offset{0}; + std::size_t len = text.getLength(); + + if ( pos >= len ) + pos = len - 1; + + while ( pos > 0 && input_width > 0 ) + { + std::size_t char_width = getColumnWidth(text[pos]); + + if ( input_width >= char_width ) + input_width -= char_width; + + if ( input_width == 0 ) + break; + + if ( input_width == 1) + { + if ( char_width == 1 ) + { + if ( pos > 0 && getColumnWidth(text[pos - 1]) == 2 ) + { + fullwidth_char_offset = 1; + break; + } + } + + if ( char_width == 2 ) + { + fullwidth_char_offset = 1; + break; + } + } + + pos--; + } + + return offsetPair(pos, fullwidth_char_offset); +} + +//---------------------------------------------------------------------- +std::size_t FLineEdit::clickPosToCursorPos (std::size_t pos) +{ + std::size_t click_width{0}; + std::size_t idx = text_offset; + std::size_t len = text.getLength(); + pos -= char_width_offset; + + while ( click_width < pos && idx < len ) + { + std::size_t char_width = getColumnWidth(text[idx]); + idx++; + click_width += char_width; + + if ( char_width == 2 && click_width == pos + 1) + idx--; + } + + return idx; +} + +//---------------------------------------------------------------------- +void FLineEdit::adjustTextOffset() +{ + std::size_t input_width = getWidth() - 2; + std::size_t len = text.getLength(); + std::size_t len_column = getColumnWidth (text); + std::size_t text_offset_column = getColumnWidth (text, text_offset); + std::size_t cursor_pos_column = getColumnWidth (text, cursor_pos); + std::size_t first_char_width{0}; + std::size_t cursor_char_width{1}; + char_width_offset = 0; + + if ( cursor_pos < len ) + cursor_char_width = getColumnWidth(text[cursor_pos]); + + if ( len > 0 ) + first_char_width = getColumnWidth(text[0]); + + // Text alignment right for long lines + while ( text_offset > 0 && len_column - text_offset_column < input_width ) + { + text_offset--; + text_offset_column = getColumnWidth (text, text_offset); + } + + // Right cursor overflow + if ( cursor_pos_column + 1 > text_offset_column + input_width ) + { + offsetPair offset_pair = endPosToOffset(cursor_pos); + text_offset = offset_pair.first; + char_width_offset = offset_pair.second; + text_offset_column = getColumnWidth (text, text_offset); + } + + // Right full-width cursor overflow + if ( cursor_pos_column + 2 > text_offset_column + input_width + && cursor_char_width == 2 ) + { + text_offset++; + + if ( first_char_width == 2 ) + char_width_offset = 1; // Deletes a half character at the beginning + } + + // Left cursor underflow + if ( text_offset > cursor_pos ) + text_offset = cursor_pos; +} + +//---------------------------------------------------------------------- +inline void FLineEdit::cursorLeft() { if ( cursor_pos > 0 ) cursor_pos--; - if ( cursor_pos < text_offset ) - text_offset--; + adjustTextOffset(); } //---------------------------------------------------------------------- -inline void FLineEdit::keyRight() +inline void FLineEdit::cursorRight() { - std::size_t len = text.getLength(); + auto len = text.getLength(); if ( cursor_pos < len ) cursor_pos++; - if ( cursor_pos - text_offset + 2 >= getWidth() - && text_offset <= len - getWidth() + 1 ) - text_offset++; + adjustTextOffset(); } //---------------------------------------------------------------------- -inline void FLineEdit::keyHome() +inline void FLineEdit::cursorHome() { cursor_pos = 0; text_offset = 0; + char_width_offset = 0; } //---------------------------------------------------------------------- -inline void FLineEdit::keyEnd() +inline void FLineEdit::cursorEnd() { - std::size_t len = text.getLength(); + auto len = text.getLength(); + + if ( cursor_pos == len ) + return; + cursor_pos = len; - - if ( cursor_pos + 1 >= getWidth() ) - text_offset = len - getWidth() + 2; - else - text_offset = 0; + adjustTextOffset(); } //---------------------------------------------------------------------- -inline void FLineEdit::keyDel() +inline void FLineEdit::deleteCurrentCharacter() { - std::size_t len = text.getLength(); + // Delete key functionality + + auto len = text.getLength(); if ( len > 0 && cursor_pos < len ) { @@ -822,38 +971,34 @@ inline void FLineEdit::keyDel() if ( cursor_pos >= len ) cursor_pos = len; - if ( text_offset > 0 && len - text_offset + 1 < getWidth() ) - text_offset--; + adjustTextOffset(); } //---------------------------------------------------------------------- -inline void FLineEdit::keyBackspace() +inline void FLineEdit::deletePreviousCharacter() { - if ( text.getLength() > 0 && cursor_pos > 0 ) - { - text.remove(cursor_pos - 1, 1); - cursor_pos--; + // Backspace functionality - if ( text_offset > 0 ) - text_offset--; + if ( text.getLength() == 0 || cursor_pos == 0 ) + return; - processChanged(); - } + cursorLeft(); + deleteCurrentCharacter(); } //---------------------------------------------------------------------- -inline void FLineEdit::keyInsert() +inline void FLineEdit::switchInsertMode() { insert_mode = ! insert_mode; if ( insert_mode ) - setInsertCursor(); + setInsertCursor(); // Insert mode else - unsetInsertCursor(); + unsetInsertCursor(); // Overtype mode } //---------------------------------------------------------------------- -inline void FLineEdit::keyEnter() +inline void FLineEdit::acceptInput() { processActivate(); } @@ -869,28 +1014,28 @@ inline bool FLineEdit::keyInput (FKey key) if ( key >= 0x20 && key <= 0x10fff ) { - std::size_t len = text.getLength(); - wchar_t c = characterFilter(wchar_t(key)); + auto len = text.getLength(); + auto ch = characterFilter(wchar_t(key)); - if ( c == L'\0' ) + if ( ch == L'\0' ) return false; else if ( cursor_pos == len ) - text += c; + text += ch; else if ( len > 0 ) { if ( insert_mode ) - text.insert(c, cursor_pos); + { + text.insert(ch, cursor_pos); + len++; + } else - text.overwrite(c, cursor_pos); + text.overwrite(ch, cursor_pos); } else - text.setString(c); + text.setString(ch); cursor_pos++; - - if ( cursor_pos + 1 >= getWidth() ) - text_offset++; - + adjustTextOffset(); processChanged(); return true; } diff --git a/src/flistbox.cpp b/src/flistbox.cpp index 10107e90..baba5fc9 100644 --- a/src/flistbox.cpp +++ b/src/flistbox.cpp @@ -140,13 +140,13 @@ void FListBox::showInsideBrackets ( std::size_t index if ( b == fc::NoBrackets ) return; - std::size_t len = iter->getText().getLength() + 2; + std::size_t column_width = getColumnWidth(iter->getText()) + 2; - if ( len > max_line_width ) + if ( column_width > max_line_width ) { - max_line_width = len; + max_line_width = column_width; - if ( len >= getWidth() - nf_offset - 3 ) + if ( column_width >= getWidth() - nf_offset - 3 ) { int hmax = ( max_line_width > getWidth() - nf_offset - 4 ) ? int(max_line_width - getWidth() + nf_offset + 4) @@ -222,9 +222,9 @@ void FListBox::hide() //---------------------------------------------------------------------- void FListBox::insert (FListBoxItem listItem) { - std::size_t len = listItem.text.getLength(); - bool has_brackets = bool(listItem.brackets); - recalculateHorizontalBar (len, has_brackets); + std::size_t column_width = getColumnWidth(listItem.text); + bool has_brackets(listItem.brackets); + recalculateHorizontalBar (column_width, has_brackets); itemlist.push_back (listItem); @@ -244,10 +244,10 @@ void FListBox::remove (std::size_t item) for (auto&& listbox_item : itemlist) { - std::size_t len = listbox_item.getText().getLength(); + std::size_t column_width = getColumnWidth(listbox_item.getText()); - if ( len > max_line_width ) - max_line_width = len; + if ( column_width > max_line_width ) + max_line_width = column_width; } int hmax = ( max_line_width > getWidth() - nf_offset - 4 ) @@ -284,7 +284,6 @@ void FListBox::remove (std::size_t item) //---------------------------------------------------------------------- void FListBox::clear() { - std::size_t size; itemlist.clear(); itemlist.shrink_to_fit(); current = 0; @@ -303,9 +302,9 @@ void FListBox::clear() hbar->hide(); // clear list from screen - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.list_fg, wc.list_bg); - size = getWidth() - 2; + std::size_t size = getWidth() - 2; if ( size == 0 ) return; @@ -335,69 +334,69 @@ void FListBox::onKeyPress (FKeyEvent* ev) { case fc::Fkey_return: case fc::Fkey_enter: - keyEnter(); + acceptSelection(); ev->accept(); break; case fc::Fkey_up: - keyUp(); + onePosUp(); ev->accept(); break; case fc::Fkey_down: - keyDown(); + onePosDown(); ev->accept(); break; case fc::Fkey_left: - keyLeft(); + scrollLeft(); ev->accept(); break; case fc::Fkey_right: - keyRight(); + scrollRight(); ev->accept(); break; case fc::Fkey_ppage: - keyPgUp(); + onePageUp(); ev->accept(); break; case fc::Fkey_npage: - keyPgDn(); + onePageDown(); ev->accept(); break; case fc::Fkey_home: - keyHome(); + firstPos(); ev->accept(); break; case fc::Fkey_end: - keyEnd(); + lastPos(); ev->accept(); break; case fc::Fkey_ic: // insert key - if ( keyInsert() ) + if ( changeSelectionAndPosition() ) ev->accept(); break; case fc::Fkey_space: - if ( keySpace() ) + if ( spacebarProcessing() ) ev->accept(); break; case fc::Fkey_erase: case fc::Fkey_backspace: - if ( keyBackspace() ) + if ( deletePreviousCharacter() ) ev->accept(); break; case fc::Fkey_escape: case fc::Fkey_escape_mintty: - if ( keyEsc() ) + if ( skipIncrementalSearch() ) ev->accept(); break; @@ -416,8 +415,8 @@ void FListBox::onKeyPress (FKeyEvent* ev) if ( ev->isAccepted() ) { - bool draw_vbar = yoffset_before != yoffset; - bool draw_hbar = xoffset_before != xoffset; + bool draw_vbar( yoffset_before != yoffset ); + bool draw_hbar( xoffset_before != xoffset ); updateDrawing (draw_vbar, draw_hbar); } } @@ -758,7 +757,7 @@ void FListBox::init() initScrollbar (vbar, fc::vertical, &FListBox::cb_VBarChange); initScrollbar (hbar, fc::horizontal, &FListBox::cb_HBarChange); setGeometry (FPoint(1, 1), FSize(5, 4), false); // initialize geometry values - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.dialog_fg); setBackgroundColor (wc.dialog_bg); nf_offset = isNewFont() ? 1 : 0; @@ -874,21 +873,21 @@ void FListBox::drawHeadline() return; FString txt(" " + text + " "); - std::size_t length = txt.getLength(); + auto column_width = getColumnWidth(txt); print() << FPoint(2, 1); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( isEnabled() ) setColor(wc.label_emphasis_fg, wc.label_bg); else setColor(wc.label_inactive_fg, wc.label_inactive_bg); - if ( length <= uInt(getClientWidth()) ) + if ( column_width <= getClientWidth() ) print (txt); else { // Print ellipsis - print() << text.left(uInt(getClientWidth() - 2)) + print() << getColumnSubString (text, 1, getClientWidth() - 2) << FColorPair (wc.label_ellipsis_fg, wc.label_bg) << ".."; } } @@ -900,7 +899,7 @@ void FListBox::drawList() return; std::size_t start{}; - std::size_t num = uInt(getHeight() - 2); + std::size_t num(getHeight() - 2); if ( num > getCount() ) num = getCount(); @@ -954,12 +953,12 @@ inline void FListBox::drawListLine ( int y , bool serach_mark ) { std::size_t inc_len = inc_search.getLength(); - const FWidgetColors& wc = getFWidgetColors(); - bool isCurrentLine = bool(y + yoffset + 1 == int(current)); - FString element (getString(iter).mid ( std::size_t(xoffset) + 1 - , getWidth() - nf_offset - 4 )); - const wchar_t* const& element_str = element.wc_str(); - std::size_t len = element.getLength(); + const auto& wc = getFWidgetColors(); + bool isCurrentLine( y + yoffset + 1 == int(current) ); + std::size_t first = std::size_t(xoffset) + 1; + std::size_t max_width = getWidth() - nf_offset - 4; + FString element(getColumnSubString (getString(iter), first, max_width)); + std::size_t column_width = getColumnWidth(element); if ( isMonochron() && isCurrentLine && getFlags().focus ) print (fc::BlackRightPointingPointer); // ► @@ -970,24 +969,22 @@ inline void FListBox::drawListLine ( int y setColor ( wc.current_inc_search_element_fg , wc.current_element_focus_bg ); - std::size_t i{}; - - for (i = 0; i < len; i++) + for (std::size_t i{0}; i < element.getLength(); i++) { if ( serach_mark && i == inc_len && getFlags().focus ) setColor ( wc.current_element_focus_fg , wc.current_element_focus_bg ); - print (element_str[i]); + print (element[i]); } if ( isMonochron() && isCurrentLine && getFlags().focus ) { print (fc::BlackLeftPointingPointer); // ◄ - i++; + column_width++; } - for (; i < getWidth() - nf_offset - 3; i++) + for (; column_width < getWidth() - nf_offset - 3; column_width++) print (' '); } @@ -1010,10 +1007,9 @@ inline void FListBox::drawListBracketsLine ( int y , listBoxItems::iterator iter , bool serach_mark ) { - FString element{}; std::size_t inc_len = inc_search.getLength() , b{0}; - bool isCurrentLine = bool(y + yoffset + 1 == int(current)); + bool isCurrentLine( y + yoffset + 1 == int(current) ); if ( isMonochron() && isCurrentLine && getFlags().focus ) print (fc::BlackRightPointingPointer); // ► @@ -1022,23 +1018,19 @@ inline void FListBox::drawListBracketsLine ( int y if ( xoffset == 0 ) { - b = 1; + b = 1; // Required bracket space printLeftBracket (iter->brackets); - - element = getString(iter).mid ( std::size_t(xoffset) + 1 - , getWidth() - nf_offset - 5 ); } - else - element = getString(iter).mid ( std::size_t(xoffset) - , getWidth() - nf_offset - 4 ); - const wchar_t* const& element_str = element.wc_str(); - std::size_t full_length = getString(iter).getLength() - , len = element.getLength() - , i{0}; - const FWidgetColors& wc = getFWidgetColors(); + std::size_t first = std::size_t(xoffset); + std::size_t max_width = getWidth() - nf_offset - 4 - b; + FString element(getColumnSubString (getString(iter), first, max_width)); + std::size_t column_width = getColumnWidth(element); + std::size_t text_width = getColumnWidth(getString(iter)); + std::size_t i{0}; + const auto& wc = getFWidgetColors(); - for (; i < len; i++) + for (; i < element.getLength(); i++) { if ( serach_mark && i == 0 ) setColor ( wc.current_inc_search_element_fg @@ -1048,27 +1040,27 @@ inline void FListBox::drawListBracketsLine ( int y setColor ( wc.current_element_focus_fg , wc.current_element_focus_bg ); - print (element_str[i]); + print (element[i]); } - if ( b + i < getWidth() - nf_offset - 4 - && std::size_t(xoffset) <= full_length + 1 ) + if ( b + column_width < getWidth() - nf_offset - 4 + && std::size_t(xoffset) <= text_width ) { if ( serach_mark && i == inc_len ) setColor ( wc.current_element_focus_fg , wc.current_element_focus_bg ); printRightBracket (iter->brackets); - i++; + column_width++; } if ( isMonochron() && isCurrentLine && getFlags().focus ) { print (fc::BlackLeftPointingPointer); // ◄ - i++; + column_width++; } - for (; b + i < getWidth() - nf_offset - 3; i++) + for (; b + column_width < getWidth() - nf_offset - 3; column_width++) print (' '); } @@ -1078,9 +1070,10 @@ inline void FListBox::setLineAttributes ( int y , bool lineHasBrackets , bool& serach_mark ) { - bool isCurrentLine = bool(y + yoffset + 1 == int(current)); + bool isCurrentLine( y + yoffset + 1 == int(current) ); std::size_t inc_len = inc_search.getLength(); - const FWidgetColors& wc = getFWidgetColors(); + std::size_t inc_width = getColumnWidth(inc_search); + const auto& wc = getFWidgetColors(); print() << FPoint(2, 2 + int(y)); if ( isLineSelected ) @@ -1131,7 +1124,7 @@ inline void FListBox::setLineAttributes ( int y { serach_mark = true; // Place the cursor on the last found character - setCursorPos (FPoint(2 + b + int(inc_len), 2 + int(y))); + setCursorPos (FPoint(2 + b + int(inc_width), 2 + int(y))); } else // only highlighted setCursorPos (FPoint(3 + b, 2 + int(y))); // first character @@ -1554,35 +1547,35 @@ void FListBox::scrollRight (int distance) } //---------------------------------------------------------------------- -inline void FListBox::keyUp() -{ - prevListItem (1); - inc_search.clear(); -} - -//---------------------------------------------------------------------- -inline void FListBox::keyDown() -{ - nextListItem (1); - inc_search.clear(); -} - -//---------------------------------------------------------------------- -inline void FListBox::keyLeft() +inline void FListBox::scrollLeft() { scrollLeft(1); inc_search.clear(); } //---------------------------------------------------------------------- -inline void FListBox::keyRight() +inline void FListBox::scrollRight() { scrollRight(1); inc_search.clear(); } //---------------------------------------------------------------------- -inline void FListBox::keyPgUp() +inline void FListBox::onePosUp() +{ + prevListItem (1); + inc_search.clear(); +} + +//---------------------------------------------------------------------- +inline void FListBox::onePosDown() +{ + nextListItem (1); + inc_search.clear(); +} + +//---------------------------------------------------------------------- +inline void FListBox::onePageUp() { int pagesize = int(getClientHeight()) - 1; prevListItem (pagesize); @@ -1590,7 +1583,7 @@ inline void FListBox::keyPgUp() } //---------------------------------------------------------------------- -inline void FListBox::keyPgDn() +inline void FListBox::onePageDown() { int pagesize = int(getClientHeight()) - 1; nextListItem (pagesize); @@ -1598,7 +1591,7 @@ inline void FListBox::keyPgDn() } //---------------------------------------------------------------------- -inline void FListBox::keyHome() +inline void FListBox::firstPos() { current = 1; yoffset = 0; @@ -1606,7 +1599,7 @@ inline void FListBox::keyHome() } //---------------------------------------------------------------------- -inline void FListBox::keyEnd() +inline void FListBox::lastPos() { std::size_t element_count = getCount(); int yoffset_end = int(element_count - getClientHeight()); @@ -1619,7 +1612,7 @@ inline void FListBox::keyEnd() } //---------------------------------------------------------------------- -inline bool FListBox::keyEsc() +inline bool FListBox::skipIncrementalSearch() { if ( inc_search.getLength() > 0 ) { @@ -1631,18 +1624,18 @@ inline bool FListBox::keyEsc() } //---------------------------------------------------------------------- -inline void FListBox::keyEnter() +inline void FListBox::acceptSelection() { processClick(); inc_search.clear(); } //---------------------------------------------------------------------- -inline bool FListBox::keySpace() +inline bool FListBox::spacebarProcessing() { std::size_t inc_len = inc_search.getLength(); - if ( inc_len > 0 ) + if ( inc_len > 0 ) // Enter a spacebar for incremental search { inc_search += L' '; bool inc_found{false}; @@ -1668,7 +1661,7 @@ inline bool FListBox::keySpace() return false; } } - else if ( isMultiSelection() ) + else if ( isMultiSelection() ) // Change selection { if ( isSelected(current) ) unselectItem(current); @@ -1683,7 +1676,7 @@ inline bool FListBox::keySpace() } //---------------------------------------------------------------------- -inline bool FListBox::keyInsert() +inline bool FListBox::changeSelectionAndPosition() { if ( isMultiSelection() ) { @@ -1711,7 +1704,7 @@ inline bool FListBox::keyInsert() } //---------------------------------------------------------------------- -inline bool FListBox::keyBackspace() +inline bool FListBox::deletePreviousCharacter() { std::size_t inc_len = inc_search.getLength(); @@ -1810,8 +1803,8 @@ void FListBox::lazyConvert(listBoxItems::iterator iter, int y) return; convertToItem (*iter, source_container, y + yoffset); - std::size_t len = iter->text.getLength(); - recalculateHorizontalBar (len, hasBrackets(iter)); + std::size_t column_width = getColumnWidth(iter->text); + recalculateHorizontalBar (column_width, hasBrackets(iter)); if ( hbar->isShown() ) hbar->redraw(); diff --git a/src/flistview.cpp b/src/flistview.cpp index 4dda2224..3b676bcc 100644 --- a/src/flistview.cpp +++ b/src/flistview.cpp @@ -232,7 +232,7 @@ FString FListViewItem::getText (int column) const return fc::emptyFString::get(); // Convert column position to address offset (index) - std::size_t index = uInt(column - 1); + std::size_t index = std::size_t(column - 1); return column_list[index]; } @@ -259,7 +259,7 @@ void FListViewItem::setText (int column, const FString& text) return; // Convert column position to address offset (index) - std::size_t index = uInt(column - 1); + std::size_t index = std::size_t(column - 1); auto parent = getParent(); if ( parent && parent->isInstanceOf("FListView") ) @@ -268,10 +268,10 @@ void FListViewItem::setText (int column, const FString& text) if ( ! listview->header[index].fixed_width ) { - int length = int(text.getLength()); + int column_width = int(getColumnWidth(text)); - if ( length > listview->header[index].width ) - listview->header[index].width = length; + if ( column_width > listview->header[index].width ) + listview->header[index].width = column_width; } } @@ -596,13 +596,11 @@ FListView::~FListView() // destructor std::size_t FListView::getCount() { int n{0}; - auto iter = itemlist.begin(); - while ( iter != itemlist.end() ) + for (auto&& item : itemlist) { - auto item = static_cast(*iter); - n += item->getVisibleLines(); - ++iter; + auto listitem = static_cast(item); + n += listitem->getVisibleLines(); } return std::size_t(n); @@ -617,7 +615,7 @@ fc::text_alignment FListView::getColumnAlignment (int column) const return fc::alignLeft; // Convert column position to address offset (index) - std::size_t index = uInt(column - 1); + std::size_t index = std::size_t(column - 1); return header[index].alignment; } @@ -630,7 +628,7 @@ FString FListView::getColumnText (int column) const return fc::emptyFString::get(); // Convert column position to address offset (index) - std::size_t index = uInt(column - 1); + std::size_t index = std::size_t(column - 1); return header[index].name; } @@ -698,10 +696,10 @@ void FListView::setColumnText (int column, const FString& label) if ( ! header[index].fixed_width ) { - int length = int(label.getLength()); + int column_width = int(getColumnWidth(label)); - if ( length > header[index].width ) - header[index].width = length; + if ( column_width > header[index].width ) + header[index].width = column_width; } header[index].name = label; @@ -715,7 +713,7 @@ void FListView::setColumnSortType (int column, fc::sorting_type type) if ( column < 1 || header.empty() || column > int(header.size()) ) return; - std::size_t size = std::size_t(column) + 1; + std::size_t size = std::size_t(column + 1); if ( sort_type.empty() || sort_type.size() < size ) sort_type.resize(size); @@ -745,7 +743,7 @@ int FListView::addColumn (const FString& label, int width) if ( new_column.width == USE_MAX_SIZE ) { new_column.fixed_width = false; - new_column.width = int(label.getLength()); + new_column.width = int(getColumnWidth(label)); } else new_column.fixed_width = true; @@ -895,7 +893,7 @@ void FListView::onKeyPress (FKeyEvent* ev) break; case fc::Fkey_space: - keySpace(); + toggleCheckbox(); ev->accept(); break; @@ -910,12 +908,12 @@ void FListView::onKeyPress (FKeyEvent* ev) break; case fc::Fkey_left: - keyLeft (first_line_position_before); + collapseAndScrollLeft (first_line_position_before); ev->accept(); break; case fc::Fkey_right: - keyRight(first_line_position_before); + expandAndScrollRight (first_line_position_before); ev->accept(); break; @@ -930,22 +928,22 @@ void FListView::onKeyPress (FKeyEvent* ev) break; case fc::Fkey_home: - keyHome(); + firstPos(); ev->accept(); break; case fc::Fkey_end: - keyEnd(); + lastPos(); ev->accept(); break; case int('+'): - if ( keyPlus() ) + if ( expandSubtree() ) ev->accept(); break; case int('-'): - if ( keyMinus() ) + if ( collapseSubtree() ) ev->accept(); break; @@ -958,9 +956,9 @@ void FListView::onKeyPress (FKeyEvent* ev) if ( ev->isAccepted() ) { - bool draw_vbar = first_line_position_before - != first_visible_line.getPosition(); - bool draw_hbar = xoffset_before != xoffset; + bool draw_vbar( first_line_position_before + != first_visible_line.getPosition() ); + bool draw_hbar(xoffset_before != xoffset); updateDrawing (draw_vbar, draw_hbar); } } @@ -1387,7 +1385,7 @@ void FListView::init() root = selflist.begin(); null_iter = selflist.end(); setGeometry (FPoint(1, 1), FSize(5, 4), false); // initialize geometry values - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.dialog_fg); setBackgroundColor (wc.dialog_bg); nf_offset = isNewFont() ? 1 : 0; @@ -1437,7 +1435,7 @@ void FListView::sort (Compare cmp) //---------------------------------------------------------------------- std::size_t FListView::getAlignOffset ( fc::text_alignment align - , std::size_t txt_length + , std::size_t column_width , std::size_t width ) { switch ( align ) @@ -1446,14 +1444,14 @@ std::size_t FListView::getAlignOffset ( fc::text_alignment align return 0; case fc::alignCenter: - if ( txt_length < width ) - return (width - txt_length) / 2; + if ( column_width < width ) + return (width - column_width) / 2; else return 0; case fc::alignRight: - if ( txt_length < width ) - return width - txt_length; + if ( column_width < width ) + return width - column_width; else return 0; } @@ -1536,8 +1534,6 @@ void FListView::drawScrollbars() //---------------------------------------------------------------------- void FListView::drawHeadlines() { - std::vector::const_iterator first, last; - if ( header.empty() || getHeight() <= 2 || getWidth() <= 4 @@ -1548,7 +1544,7 @@ void FListView::drawHeadlines() headerline.clear(); if ( hasCheckableItems() ) - drawHeaderBorder(4); + drawHeaderBorder(4); // Draw into FTermBuffer object while ( iter != header.end() ) { @@ -1560,27 +1556,12 @@ void FListView::drawHeadlines() continue; } - drawHeadlineLabel(iter); + drawHeadlineLabel(iter); // Draw into FTermBuffer object ++iter; } - std::vector h; - h << headerline; - first = h.begin() + xoffset; - - if ( h.size() <= getClientWidth() ) - last = h.end(); - else - { - int len = int(getClientWidth()) + xoffset - 1; - - if ( len > int(h.size()) ) - len = int(h.size()); - - last = h.begin() + len; - } - - print() << FPoint(2, 1) << std::vector(first, last); + // Print the FTermBuffer object + drawBufferedHeadline(); } //---------------------------------------------------------------------- @@ -1590,12 +1571,12 @@ void FListView::drawList() return; uInt y{0}; - uInt page_height = uInt(getHeight() - 2); + uInt page_height = uInt(getHeight()) - 2; auto iter = first_visible_line; while ( iter != itemlist.end() && y < page_height ) { - bool is_current_line = bool( iter == current_iter ); + bool is_current_line( iter == current_iter ); const auto item = static_cast(*iter); int tree_offset = ( tree_view ) ? int(item->getDepth() << 1) + 1 : 0; int checkbox_offset = ( item->isCheckable() ) ? 1 : 0; @@ -1606,9 +1587,13 @@ void FListView::drawList() if ( getFlags().focus && is_current_line ) { + int xpos = 3 + tree_offset + checkbox_offset - xoffset; + + if ( xpos < 2 ) // Hide the cursor + xpos = -9999; // by moving it outside the visible area + setVisibleCursor (item->isCheckable()); - setCursorPos (FPoint ( 3 + tree_offset + checkbox_offset - xoffset - , 2 + int(y) )); // first character + setCursorPos (FPoint(xpos, 2 + int(y))); // first character } last_visible_line = iter; @@ -1651,12 +1636,12 @@ void FListView::drawListLine ( const FListViewItem* item static constexpr std::size_t ellipsis_length = 2; const auto& text = item->column_list[col]; std::size_t width = std::size_t(header[col].width); - std::size_t txt_length = text.getLength(); - // Increment the value of i for the column position + std::size_t column_width = getColumnWidth(text); + // Increment the value of col for the column position // and the next iteration col++; fc::text_alignment align = getColumnAlignment(int(col)); - std::size_t align_offset = getAlignOffset (align, txt_length, width); + std::size_t align_offset = getAlignOffset (align, column_width, width); if ( tree_view && col == 1 ) { @@ -1673,40 +1658,43 @@ void FListView::drawListLine ( const FListViewItem* item if ( align_offset > 0 ) line += FString(align_offset, L' '); - if ( align_offset + txt_length <= width ) + if ( align_offset + column_width <= width ) { // Insert text and trailing space static constexpr std::size_t leading_space = 1; - line += text.left(width); + line += getColumnSubString (text, 1, width); line += FString ( leading_space + width - - align_offset - txt_length, L' '); + - align_offset - column_width, L' '); } else if ( align == fc::alignRight ) { // Ellipse right align text + std::size_t first = getColumnWidth(text) + 1 - width; line += FString (L".."); - line += text.right(width - ellipsis_length); + line += getColumnSubString (text, first, width - ellipsis_length); line += L' '; } else { // Ellipse left align text and center text - line += text.left(width - ellipsis_length); + line += getColumnSubString (text, 1, width - ellipsis_length); line += FString (L".. "); } } } - line = line.mid ( std::size_t(xoffset) + 1 - , getWidth() - nf_offset - 2); - const wchar_t* const& element_str = line.wc_str(); + std::size_t width = getWidth() - nf_offset - 2; + line = getColumnSubString ( line, std::size_t(xoffset) + 1, width ); std::size_t len = line.getLength(); - std::size_t i; + std::size_t char_width{0}; - for (i = 0; i < len; i++) - print() << element_str[i]; + for (std::size_t i{0}; i < len; i++) + { + char_width += getColumnWidth(line[i]); + print() << line[i]; + } - for (; i < getWidth() - nf_offset - 2; i++) + for (std::size_t i = char_width; i < width; i++) print (' '); } @@ -1714,7 +1702,7 @@ void FListView::drawListLine ( const FListViewItem* item inline void FListView::setLineAttributes ( bool is_current , bool is_focus ) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.list_fg, wc.list_bg); if ( is_current ) @@ -1805,9 +1793,9 @@ inline FString FListView::getLinePrefix ( const FListViewItem* item //---------------------------------------------------------------------- inline void FListView::drawSortIndicator ( std::size_t& length - , std::size_t column_width ) + , std::size_t column_max ) { - if ( length >= column_width ) + if ( length >= column_max ) return; setColor(); @@ -1818,7 +1806,7 @@ inline void FListView::drawSortIndicator ( std::size_t& length else if ( sort_order == fc::descending ) headerline << fc::BlackDownPointingTriangle; // ▼ - if ( length < column_width ) + if ( length < column_max ) { length++; headerline << ' '; @@ -1833,65 +1821,153 @@ inline void FListView::drawHeaderBorder (std::size_t length) headerline << line; // horizontal line } + //---------------------------------------------------------------------- void FListView::drawHeadlineLabel (const headerItems::const_iterator& iter) { - // Print lable text + // Print label text static constexpr std::size_t leading_space = 1; const auto& text = iter->name; FString txt(" " + text); std::size_t width = std::size_t(iter->width); - std::size_t txt_length = txt.getLength(); - std::size_t column_width = leading_space + width; + std::size_t column_width = getColumnWidth(txt); + std::size_t column_max = leading_space + width; headerItems::const_iterator first = header.begin(); int column = int(std::distance(first, iter)) + 1; - bool has_sort_indicator = bool ( sort_column == column - && ! hide_sort_indicator ); - const FWidgetColors& wc = getFWidgetColors(); + bool has_sort_indicator( sort_column == column && ! hide_sort_indicator ); + const auto& wc = getFWidgetColors(); if ( isEnabled() ) setColor (wc.label_emphasis_fg, wc.label_bg); else setColor (wc.label_inactive_fg, wc.label_inactive_bg); - if ( has_sort_indicator && txt_length >= column_width - 1 && txt_length > 1 ) + if ( has_sort_indicator && column_width >= column_max - 1 && column_width > 1 ) { - txt_length = column_width - 2; - txt = txt.left(txt_length); + column_width = column_max - 2; + txt = getColumnSubString (txt, 1, column_width); } - if ( txt_length <= column_width ) + if ( column_width <= column_max ) { - std::size_t length = txt_length; headerline << txt; - if ( length < column_width ) + if ( column_width < column_max ) { - length++; + column_width++; headerline << ' '; // trailing space } if ( has_sort_indicator ) - drawSortIndicator (length, column_width ); + drawSortIndicator (column_width, column_max ); - if ( length < column_width ) - drawHeaderBorder (column_width - length); + if ( column_width < column_max ) + drawHeaderBorder (column_max - column_width); } else drawColumnEllipsis (iter, text); // Print ellipsis } +//---------------------------------------------------------------------- +void FListView::drawBufferedHeadline() +{ + // Print the FTermBuffer object + + if ( headerline.isEmpty() ) + return; + + std::size_t column_offset{0}; + std::size_t column_width{0}; + std::size_t offset{0}; + bool left_truncated_fullwidth{false}; + bool right_truncated_fullwidth{false}; + std::vector::const_iterator first{}, last{}; + last = headerline.end(); + + // Search for the start position + for (auto&& tc : headerline) + { + if ( xoffset == 0 ) + break; + + column_offset += getColumnWidth(tc); + offset++; + + if ( column_offset == std::size_t(xoffset) ) + break; + + if ( column_offset > std::size_t(xoffset) && column_offset >= 2 ) + { + left_truncated_fullwidth = true; + break; + } + } + + first = headerline.begin(); + std::advance(first, offset); + + // Search for the end position + if ( getColumnWidth(headerline) > getClientWidth() ) + { + std::size_t character{0}; + + if ( left_truncated_fullwidth ) + column_width++; + + for (auto&& tc : FTermBuffer(first, last)) + { + uInt8 char_width = tc.attr.bit.char_width; + + if ( column_width + char_width > getClientWidth() ) + { + column_width++; + right_truncated_fullwidth = true; + break; + } + + column_width += char_width; + character++; + + if ( column_width == getClientWidth() ) + break; + } + + last = first; + std::advance(last, character); + } + else + column_width = getColumnWidth(headerline); + + // Print the header line + print() << FPoint(2, 1); + + if ( left_truncated_fullwidth ) + print (fc::SingleLeftAngleQuotationMark); // ‹ + + print() << FTermBuffer(first, last); + + if ( right_truncated_fullwidth ) + print (fc::SingleRightAngleQuotationMark); // › + + while ( column_width < getClientWidth() ) + { + setColor(); + print(fc::BoxDrawingsHorizontal); + column_width++; + } +} + //---------------------------------------------------------------------- void FListView::drawColumnEllipsis ( const headerItems::const_iterator& iter , const FString& text ) { - // Print lable ellipsis + // Print label ellipsis static constexpr int ellipsis_length = 2; int width = iter->width; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); headerline << ' ' - << text.left(uInt(width - ellipsis_length)) + << getColumnSubString (text, 1, uInt(width - ellipsis_length)) << FColorPair (wc.label_ellipsis_fg, wc.label_bg) << ".."; @@ -1923,33 +1999,36 @@ void FListView::updateDrawing (bool draw_vbar, bool draw_hbar) std::size_t FListView::determineLineWidth (FListViewItem* item) { static constexpr std::size_t padding_space = 1; + static constexpr std::size_t checkbox_space = 4; std::size_t line_width = padding_space; // leading space - uInt column_idx{0}; - uInt entries = uInt(item->column_list.size()); - headerItems::iterator header_iter = header.begin(); + std::size_t column_idx{0}; + std::size_t entries = std::size_t(item->column_list.size()); - while ( header_iter != header.end() ) + if ( hasCheckableItems() ) + line_width += checkbox_space; + + for (auto&& header_item : header) { - std::size_t width = std::size_t(header_iter->width); - bool fixed_width = header_iter->fixed_width; + std::size_t width = std::size_t(header_item.width); + bool fixed_width = header_item.fixed_width; if ( ! fixed_width ) { - std::size_t len; + std::size_t len{}; if ( column_idx < entries ) - len = item->column_list[column_idx].getLength(); + len = getColumnWidth(item->column_list[column_idx]); else len = 0; if ( len > width ) - header_iter->width = int(len); + header_item.width = int(len); } - line_width += std::size_t(header_iter->width) - + padding_space; // width + trailing space + // width + trailing space + line_width += std::size_t(header_item.width) + padding_space; + column_idx++; - ++header_iter; } return line_width; @@ -2033,19 +2112,18 @@ void FListView::mouseHeaderClicked() int checkbox_offset = ( hasCheckableItems() ) ? 4 : 0; int header_start = 2 + checkbox_offset; int header_pos = clicked_header_pos.getX() + xoffset; - headerItems::const_iterator iter = header.begin(); - while ( iter != header.end() ) + for (auto&& item : header) { static constexpr int leading_space = 1; - bool has_sort_indicator = bool( column == sort_column ); - int click_width = int(iter->name.getLength()); + bool has_sort_indicator( column == sort_column ); + int click_width = int(getColumnWidth(item.name)); if ( has_sort_indicator ) click_width += 2; - if ( click_width > iter->width ) - click_width = iter->width; + if ( click_width > item.width ) + click_width = item.width; if ( header_pos > header_start && header_pos <= header_start + click_width ) @@ -2063,9 +2141,8 @@ void FListView::mouseHeaderClicked() break; } - header_start += leading_space + iter->width; + header_start += leading_space + item.width; column++; - ++iter; } } @@ -2234,7 +2311,7 @@ void FListView::processChanged() } //---------------------------------------------------------------------- -inline void FListView::keySpace() +inline void FListView::toggleCheckbox() { if ( itemlist.empty() ) return; @@ -2246,7 +2323,7 @@ inline void FListView::keySpace() } //---------------------------------------------------------------------- -inline void FListView::keyLeft (int& first_line_position_before) +inline void FListView::collapseAndScrollLeft (int& first_line_position_before) { if ( itemlist.empty() ) return; @@ -2303,7 +2380,7 @@ inline void FListView::keyLeft (int& first_line_position_before) } //---------------------------------------------------------------------- -inline void FListView::keyRight (int& first_line_position_before) +inline void FListView::expandAndScrollRight (int& first_line_position_before) { if ( itemlist.empty() ) return; @@ -2331,7 +2408,7 @@ inline void FListView::keyRight (int& first_line_position_before) } //---------------------------------------------------------------------- -inline void FListView::keyHome() +inline void FListView::firstPos() { if ( itemlist.empty() ) return; @@ -2343,7 +2420,7 @@ inline void FListView::keyHome() } //---------------------------------------------------------------------- -inline void FListView::keyEnd() +inline void FListView::lastPos() { if ( itemlist.empty() ) return; @@ -2356,7 +2433,7 @@ inline void FListView::keyEnd() } //---------------------------------------------------------------------- -inline bool FListView::keyPlus() +inline bool FListView::expandSubtree() { if ( itemlist.empty() ) return false; @@ -2374,7 +2451,7 @@ inline bool FListView::keyPlus() } //---------------------------------------------------------------------- -inline bool FListView::keyMinus() +inline bool FListView::collapseSubtree() { if ( itemlist.empty() ) return false; diff --git a/src/fmenu.cpp b/src/fmenu.cpp index 6693ddfd..2a855e80 100644 --- a/src/fmenu.cpp +++ b/src/fmenu.cpp @@ -51,7 +51,7 @@ FMenu::FMenu(FWidget* parent) //---------------------------------------------------------------------- FMenu::FMenu (const FString& txt, FWidget* parent) : FWindow(parent) - , item(txt, parent) + , menuitem(txt, parent) { init(parent); } @@ -80,7 +80,7 @@ bool FMenu::setMenuWidget (bool enable) void FMenu::setStatusbarMessage (const FString& msg) { FWidget::setStatusbarMessage(msg); - item.setStatusbarMessage(msg); + menuitem.setStatusbarMessage(msg); } //---------------------------------------------------------------------- @@ -138,29 +138,29 @@ void FMenu::onKeyPress (FKeyEvent* ev) switch ( ev->key() ) { case fc::Fkey_up: - keyUp(); + selectPrevItem(); break; case fc::Fkey_down: - keyDown(); + selectNextItem(); break; case fc::Fkey_left: - keyLeft(ev); + selectPrevMenu(ev); break; case fc::Fkey_right: - keyRight(ev); + selectNextMenu(ev); break; case fc::Fkey_return: case fc::Fkey_enter: - keyEnter(); + acceptSelection(); break; case fc::Fkey_escape: case fc::Fkey_escape_mintty: - keyEscape(); + closeMenu(); break; case fc::Fmkey_1: @@ -320,12 +320,12 @@ void FMenu::onMouseMove (FMouseEvent* ev) //---------------------------------------------------------------------- void FMenu::cb_menuitem_toggled (FWidget* widget, FDataPtr) { - auto menuitem = static_cast(widget); + auto m_item = static_cast(widget); if ( ! has_checkable_items ) return; - if ( ! menuitem->isChecked() ) + if ( ! m_item->isChecked() ) return; auto list = getItemList(); @@ -333,19 +333,14 @@ void FMenu::cb_menuitem_toggled (FWidget* widget, FDataPtr) if ( list.empty() ) return; - auto iter = list.begin(); - auto last = list.end(); - - while ( iter != last ) + for (auto&& item : list) { - if ( (*iter) != menuitem - && (*iter)->isChecked() - && isRadioMenuItem(*iter) ) + if ( item != m_item + && item->isChecked() + && isRadioMenuItem(item) ) { - (*iter)->unsetChecked(); + item->unsetChecked(); } - - ++iter; } } @@ -445,10 +440,10 @@ void FMenu::init(FWidget* parent) setMenuWidget(); hide(); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.menu_active_fg); setBackgroundColor (wc.menu_active_bg); - item.setMenu(this); + menuitem.setMenu(this); if ( parent ) { @@ -472,17 +467,14 @@ void FMenu::init(FWidget* parent) //---------------------------------------------------------------------- void FMenu::calculateDimensions() { - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); max_item_width = 10; // minimum width // find the maximum item width - while ( iter != last ) + for (auto&& item : getItemList()) { - std::size_t item_width = (*iter)->getTextLength() + 2; - FKey accel_key = (*iter)->accel_key; - bool has_menu = (*iter)->hasMenu(); + std::size_t item_width = item->getTextWidth() + 2; + FKey accel_key = item->accel_key; + bool has_menu = item->hasMenu(); if ( has_menu ) { @@ -499,8 +491,6 @@ void FMenu::calculateDimensions() if ( item_width > max_item_width ) max_item_width = item_width; - - ++iter; } int adjust_X = adjustX(getX()); @@ -510,42 +500,36 @@ void FMenu::calculateDimensions() , FSize(max_item_width + 2, getCount() + 2) ); // set geometry of all items - iter = list.begin(); int item_X = 1; int item_Y = 1; - while ( iter != last ) + for (auto&& item : getItemList()) { - (*iter)->setGeometry (FPoint(item_X, item_Y), FSize(max_item_width, 1)); + item->setGeometry (FPoint(item_X, item_Y), FSize(max_item_width, 1)); - if ( (*iter)->hasMenu() ) + if ( item->hasMenu() ) { int menu_X = getTermX() + int(max_item_width) + 1; - int menu_Y = (*iter)->getTermY() - 2; + int menu_Y = item->getTermY() - 2; // set sub-menu position - (*iter)->getMenu()->setPos (FPoint(menu_X, menu_Y), false); + item->getMenu()->setPos (FPoint(menu_X, menu_Y), false); } item_Y++; - ++iter; } } //---------------------------------------------------------------------- void FMenu::adjustItems() { - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); - - while ( iter != last ) + for (auto&& item : getItemList()) { - if ( (*iter)->hasMenu() ) + if ( item->hasMenu() ) { - auto menu = (*iter)->getMenu(); + auto menu = item->getMenu(); int menu_X = getTermX() + int(max_item_width) + 1; menu_X = menu->adjustX(menu_X); - int menu_Y = (*iter)->getTermY() - 2; + int menu_Y = item->getTermY() - 2; // set sub-menu position menu->setPos (FPoint(menu_X, menu_Y)); @@ -554,8 +538,6 @@ void FMenu::adjustItems() if ( menu->getCount() > 0 ) menu->adjustItems(); } - - ++iter; } } @@ -664,16 +646,13 @@ void FMenu::hideSuperMenus() bool FMenu::mouseDownOverList (FPoint mouse_pos) { bool focus_changed{false}; - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); mouse_pos -= FPoint(getRightPadding(), getTopPadding()); - while ( iter != last ) + for (auto&& item : getItemList()) { - int x1 = (*iter)->getX() - , x2 = (*iter)->getX() + int((*iter)->getWidth()) - , y = (*iter)->getY() + int x1 = item->getX() + , x2 = item->getX() + int(item->getWidth()) + , y = item->getY() , mouse_x = mouse_pos.getX() , mouse_y = mouse_pos.getY(); @@ -682,11 +661,9 @@ bool FMenu::mouseDownOverList (FPoint mouse_pos) && mouse_y == y ) { // Mouse pointer over item - mouseDownSubmenu (*iter); - mouseDownSelection (*iter, focus_changed); + mouseDownSubmenu (item); + mouseDownSelection (item, focus_changed); } - - ++iter; } return focus_changed; @@ -753,28 +730,25 @@ void FMenu::mouseDownSelection (FMenuItem* m_item, bool& focus_changed) //---------------------------------------------------------------------- bool FMenu::mouseUpOverList (FPoint mouse_pos) { - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); mouse_pos -= FPoint(getRightPadding(), getTopPadding()); - while ( iter != last ) + for (auto&& item : getItemList()) { - int x1 = (*iter)->getX() - , x2 = (*iter)->getX() + int((*iter)->getWidth()) - , y = (*iter)->getY() + int x1 = item->getX() + , x2 = item->getX() + int(item->getWidth()) + , y = item->getY() , mouse_x = mouse_pos.getX() , mouse_y = mouse_pos.getY(); - if ( (*iter)->isSelected() + if ( item->isSelected() && mouse_x >= x1 && mouse_x < x2 && mouse_y == y ) { // Mouse pointer over item - if ( (*iter)->hasMenu() ) + if ( item->hasMenu() ) { - auto sub_menu = (*iter)->getMenu(); + auto sub_menu = item->getMenu(); if ( ! sub_menu->isShown() ) openSubMenu (sub_menu, SELECT_ITEM); else if ( opened_sub_menu ) @@ -800,11 +774,9 @@ bool FMenu::mouseUpOverList (FPoint mouse_pos) unselectItem(); hide(); hideSuperMenus(); - (*iter)->processClicked(); + item->processClicked(); } } - - ++iter; } return false; @@ -813,25 +785,20 @@ bool FMenu::mouseUpOverList (FPoint mouse_pos) //---------------------------------------------------------------------- void FMenu::mouseMoveOverList (FPoint mouse_pos, mouseStates& ms) { - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); mouse_pos -= FPoint(getRightPadding(), getTopPadding()); - while ( iter != last ) + for (auto&& item : getItemList()) { - int x1 = (*iter)->getX() - , x2 = (*iter)->getX() + int((*iter)->getWidth()) - , y = (*iter)->getY() + int x1 = item->getX() + , x2 = item->getX() + int(item->getWidth()) + , y = item->getY() , mouse_x = mouse_pos.getX() , mouse_y = mouse_pos.getY(); if ( mouse_x >= x1 && mouse_x < x2 && mouse_y == y ) - mouseMoveSelection (*iter, ms); + mouseMoveSelection (item, ms); else - mouseMoveDeselection (*iter, ms); - - ++iter; + mouseMoveDeselection (item, ms); } } @@ -1001,7 +968,7 @@ bool FMenu::containsMenuStructure (int x, int y) return true; else if ( si && si->hasMenu() && opened_sub_menu ) return si->getMenu()->containsMenuStructure(x, y); - else if ( item.getTermGeometry().contains(x, y) ) + else if ( menuitem.getTermGeometry().contains(x, y) ) return true; else return false; @@ -1038,9 +1005,8 @@ bool FMenu::selectNextItem() { auto list = getItemList(); auto iter = list.begin(); - auto last = list.end(); - while ( iter != last ) + while ( iter != list.end() ) { if ( (*iter)->isSelected() ) { @@ -1087,7 +1053,6 @@ bool FMenu::selectPrevItem() { auto list = getItemList(); auto iter = list.end(); - auto first = list.begin(); do { @@ -1127,7 +1092,7 @@ bool FMenu::selectPrevItem() break; } } - while ( iter != first ); + while ( iter != list.begin() ); return true; } @@ -1144,22 +1109,21 @@ void FMenu::keypressMenuBar (FKeyEvent* ev) //---------------------------------------------------------------------- bool FMenu::hotkeyMenu (FKeyEvent* ev) { - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); - - while ( iter != last ) + for (auto&& item : getItemList()) { - if ( (*iter)->hasHotkey() ) + if ( item->hasHotkey() ) { bool found{false}; - uChar hotkey = (*iter)->getHotkey(); + FKey hotkey = item->getHotkey(); FKey key = ev->key(); - if ( std::isalpha(hotkey) || std::isdigit(hotkey) ) + if ( hotkey > 0xff00 && hotkey < 0xff5f ) // full-width character + hotkey -= 0xfee0; + + if ( std::isalpha(int(hotkey)) || std::isdigit(int(hotkey)) ) { - if ( FKey(std::tolower(hotkey)) == key - || FKey(std::toupper(hotkey)) == key ) + if ( FKey(std::tolower(int(hotkey))) == key + || FKey(std::toupper(int(hotkey))) == key ) found = true; } else if ( hotkey == key ) @@ -1167,14 +1131,17 @@ bool FMenu::hotkeyMenu (FKeyEvent* ev) if ( found ) { - if ( (*iter)->hasMenu() ) + if ( item->hasMenu() ) { - auto sub_menu = (*iter)->getMenu(); + auto sub_menu = item->getMenu(); unselectItem(); - (*iter)->setSelected(); - setSelectedItem (*iter); + item->setSelected(); + setSelectedItem (item); redraw(); - openSubMenu (sub_menu, SELECT_ITEM); + + if ( ! sub_menu->isShown() ) + openSubMenu (sub_menu, SELECT_ITEM); + sub_menu->redraw(); } else @@ -1186,14 +1153,13 @@ bool FMenu::hotkeyMenu (FKeyEvent* ev) updateTerminal(); flush_out(); ev->accept(); - (*iter)->processClicked(); + item->processClicked(); } + ev->accept(); return true; } } - - ++iter; } return false; @@ -1203,7 +1169,7 @@ bool FMenu::hotkeyMenu (FKeyEvent* ev) void FMenu::draw() { // Fill the background - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.menu_active_fg, wc.menu_active_bg); if ( isMonochron() ) @@ -1222,18 +1188,14 @@ void FMenu::draw() void FMenu::drawItems() { int y = 0; - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); - while ( iter != last ) + for (auto&& item : getItemList()) { - if ( (*iter)->isSeparator() ) + if ( item->isSeparator() ) drawSeparator (y); else - drawMenuLine (*iter, y); + drawMenuLine (item, y); - ++iter; y++; } } @@ -1241,7 +1203,7 @@ void FMenu::drawItems() //---------------------------------------------------------------------- inline void FMenu::drawSeparator (int y) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); print() << FPoint(1, 2 + y) << FColorPair(wc.menu_active_fg, wc.menu_active_bg); @@ -1270,21 +1232,22 @@ inline void FMenu::drawSeparator (int y) } //---------------------------------------------------------------------- -inline void FMenu::drawMenuLine (FMenuItem* menuitem, int y) +inline void FMenu::drawMenuLine (FMenuItem* m_item, int y) { - FString txt(menuitem->getText()); + FString txt(m_item->getText()); menuText txtdata{}; std::size_t txt_length = txt.getLength(); std::size_t to_char = txt_length; - FKey accel_key = menuitem->accel_key; - bool is_enabled = menuitem->isEnabled(); - bool is_selected = menuitem->isSelected(); + std::size_t column_width = getColumnWidth(txt); + FKey accel_key = m_item->accel_key; + bool is_enabled = m_item->isEnabled(); + bool is_selected = m_item->isSelected(); // Set screen position and attributes - setLineAttributes (menuitem, y); + setLineAttributes (m_item, y); // Draw check mark prefix for checkable items - drawCheckMarkPrefix (menuitem); + drawCheckMarkPrefix (m_item); // Print leading blank space print (' '); @@ -1302,11 +1265,14 @@ inline void FMenu::drawMenuLine (FMenuItem* menuitem, int y) hotkeypos = finalcut::getHotkeyPos(txt.wc_str(), txtdata.text, txt_length); if ( hotkeypos != NOT_SET ) + { to_char--; + column_width--; + } txtdata.length = to_char; - txtdata.no_underline = menuitem->getFlags().no_underline; - setCursorToHotkeyPosition (menuitem); + txtdata.no_underline = m_item->getFlags().no_underline; + setCursorToHotkeyPosition (m_item); if ( ! is_enabled || is_selected ) txtdata.hotkeypos = NOT_SET; @@ -1315,14 +1281,14 @@ inline void FMenu::drawMenuLine (FMenuItem* menuitem, int y) drawMenuText (txtdata); - if ( menuitem->hasMenu() ) - drawSubMenuIndicator (to_char); + if ( m_item->hasMenu() ) + drawSubMenuIndicator (column_width); else if ( accel_key ) - drawAcceleratorKey (to_char, accel_key); + drawAcceleratorKey (column_width, accel_key); // Draw the trailing spaces of the selected line if ( is_selected ) - drawTrailingSpaces (to_char); + drawTrailingSpaces (column_width); if ( isMonochron() && is_enabled && is_selected ) setReverse(true); @@ -1331,11 +1297,11 @@ inline void FMenu::drawMenuLine (FMenuItem* menuitem, int y) } //---------------------------------------------------------------------- -inline void FMenu::drawCheckMarkPrefix (FMenuItem* menuitem) +inline void FMenu::drawCheckMarkPrefix (FMenuItem* m_item) { - bool is_checked = menuitem->isChecked(); - bool is_checkable = menuitem->checkable; - bool is_radio_btn = menuitem->radio_button; + bool is_checked = m_item->isChecked(); + bool is_checkable = m_item->checkable; + bool is_radio_btn = m_item->radio_button; if ( ! has_checkable_items ) return; @@ -1361,7 +1327,7 @@ inline void FMenu::drawCheckMarkPrefix (FMenuItem* menuitem) } else { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.menu_inactive_fg, getBackgroundColor()); if ( getEncoding() == fc::ASCII ) @@ -1383,7 +1349,7 @@ inline void FMenu::drawMenuText (menuText& data) for (std::size_t z{0}; z < data.length; z++) { - if ( ! std::iswprint(wint_t(data.text[z])) ) + if ( ! std::iswprint(std::wint_t(data.text[z])) ) { if ( ! isNewFont() && ( int(data.text[z]) < fc::NF_rev_left_arrow2 @@ -1396,7 +1362,7 @@ inline void FMenu::drawMenuText (menuText& data) if ( z == data.hotkeypos ) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.menu_hotkey_fg, wc.menu_hotkey_bg); if ( ! data.no_underline ) @@ -1458,11 +1424,11 @@ inline void FMenu::drawTrailingSpaces (std::size_t startpos) } //---------------------------------------------------------------------- -inline void FMenu::setLineAttributes (FMenuItem* menuitem, int y) +inline void FMenu::setLineAttributes (FMenuItem* m_item, int y) { - bool is_enabled = menuitem->isEnabled(); - bool is_selected = menuitem->isSelected(); - const FWidgetColors& wc = getFWidgetColors(); + bool is_enabled = m_item->isEnabled(); + bool is_selected = m_item->isSelected(); + const auto& wc = getFWidgetColors(); if ( is_enabled ) { @@ -1497,10 +1463,10 @@ inline void FMenu::setLineAttributes (FMenuItem* menuitem, int y) } //---------------------------------------------------------------------- -inline void FMenu::setCursorToHotkeyPosition (FMenuItem* menuitem) +inline void FMenu::setCursorToHotkeyPosition (FMenuItem* m_item) { - bool is_checkable = menuitem->checkable; - bool is_selected = menuitem->isSelected(); + bool is_checkable = m_item->checkable; + bool is_selected = m_item->isSelected(); if ( hotkeypos == NOT_SET ) { @@ -1508,9 +1474,9 @@ inline void FMenu::setCursorToHotkeyPosition (FMenuItem* menuitem) if ( is_selected ) { if ( is_checkable ) - menuitem->setCursorPos (FPoint(3, 1)); + m_item->setCursorPos (FPoint(3, 1)); else - menuitem->setCursorPos (FPoint(2, 1)); + m_item->setCursorPos (FPoint(2, 1)); } } else @@ -1518,28 +1484,18 @@ inline void FMenu::setCursorToHotkeyPosition (FMenuItem* menuitem) if ( is_selected ) { // set cursor to the hotkey position + auto x = getColumnWidth (m_item->getText(), hotkeypos); + if ( is_checkable ) - menuitem->setCursorPos (FPoint(3 + int(hotkeypos), 1)); + m_item->setCursorPos (FPoint(3 + int(x), 1)); else - menuitem->setCursorPos (FPoint(2 + int(hotkeypos), 1)); + m_item->setCursorPos (FPoint(2 + int(x), 1)); } } } //---------------------------------------------------------------------- -inline void FMenu::keyUp() -{ - selectPrevItem(); -} - -//---------------------------------------------------------------------- -inline void FMenu::keyDown() -{ - selectNextItem(); -} - -//---------------------------------------------------------------------- -inline void FMenu::keyLeft (FKeyEvent* ev) +inline void FMenu::selectPrevMenu (FKeyEvent* ev) { if ( isSubMenu() ) { @@ -1563,7 +1519,7 @@ inline void FMenu::keyLeft (FKeyEvent* ev) } //---------------------------------------------------------------------- -inline void FMenu::keyRight (FKeyEvent* ev) +inline void FMenu::selectNextMenu (FKeyEvent* ev) { if ( hasSelectedItem() && getSelectedItem()->hasMenu() ) { @@ -1579,7 +1535,7 @@ inline void FMenu::keyRight (FKeyEvent* ev) } //---------------------------------------------------------------------- -inline void FMenu::keyEnter() +inline void FMenu::acceptSelection() { if ( ! hasSelectedItem() ) return; @@ -1598,7 +1554,7 @@ inline void FMenu::keyEnter() } //---------------------------------------------------------------------- -inline void FMenu::keyEscape() +inline void FMenu::closeMenu() { unselectItem(); hideSubMenus(); diff --git a/src/fmenubar.cpp b/src/fmenubar.cpp index 5e65bf2e..b9eac303 100644 --- a/src/fmenubar.cpp +++ b/src/fmenubar.cpp @@ -65,7 +65,7 @@ void FMenuBar::resetMenu() void FMenuBar::hide() { FWindow::hide(); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); FColor fg = wc.term_fg; FColor bg = wc.term_bg; setColor (fg, bg); @@ -250,7 +250,7 @@ void FMenuBar::init() addAccelerator (fc::Fkey_f10); addAccelerator (fc::Fckey_space); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.menu_active_fg); setBackgroundColor (wc.menu_active_bg); unsetFocusable(); @@ -260,26 +260,21 @@ void FMenuBar::init() void FMenuBar::calculateDimensions() { FPoint item_pos (1, 1); - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); // find the maximum item width - while ( iter != last ) + for (auto&& item : getItemList()) { - std::size_t len = (*iter)->getTextLength(); - int item_width = int(len) + 2; + int len = int(item->getTextWidth()); + int item_width = len + 2; // set item geometry - (*iter)->setGeometry (item_pos, FSize(std::size_t(item_width), 1), false); + item->setGeometry (item_pos, FSize(std::size_t(item_width), 1), false); // set menu position - if ( (*iter)->hasMenu() ) - (*iter)->getMenu()->setPos (item_pos, false); + if ( item->hasMenu() ) + item->getMenu()->setPos (item_pos, false); item_pos.x_ref() += item_width; - - ++iter; } } @@ -288,9 +283,8 @@ bool FMenuBar::selectNextItem() { auto list = getItemList(); auto iter = list.begin(); - auto last = list.end(); - while ( iter != last ) + while ( iter != list.end() ) { if ( (*iter)->isSelected() ) { @@ -351,7 +345,6 @@ bool FMenuBar::selectPrevItem() { auto list = getItemList(); auto iter = list.end(); - auto first = list.begin(); do { @@ -405,7 +398,7 @@ bool FMenuBar::selectPrevItem() break; } } - while ( iter != first ); + while ( iter != list.begin() ); return true; } @@ -413,18 +406,17 @@ bool FMenuBar::selectPrevItem() //---------------------------------------------------------------------- bool FMenuBar::hotkeyMenu (FKeyEvent*& ev) { - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); - - while ( iter != last ) + for (auto&& item : getItemList()) { - if ( (*iter)->isEnabled() ) + if ( item->isEnabled() ) { - uChar hotkey = (*iter)->getHotkey(); + FKey hotkey = item->getHotkey(); FKey key = ev->key(); - if ( fc::Fmkey_meta + FKey(std::tolower(hotkey)) == key ) + if ( hotkey > 0xff00 && hotkey < 0xff5f ) // full-width character + hotkey -= 0xfee0; + + if ( fc::Fmkey_meta + FKey(std::tolower(int(hotkey))) == key ) { auto sel_item = getSelectedItem(); @@ -433,13 +425,13 @@ bool FMenuBar::hotkeyMenu (FKeyEvent*& ev) unselectItem(); - if ( (*iter)->hasMenu() ) + if ( item->hasMenu() ) { - auto menu = (*iter)->getMenu(); - (*iter)->setSelected(); - setSelectedItem(*iter); - (*iter)->setFocus(); - (*iter)->openMenu(); + auto menu = item->getMenu(); + item->setSelected(); + setSelectedItem(item); + item->setFocus(); + item->openMenu(); menu->selectFirstItem(); auto first_item = menu->getSelectedItem(); @@ -459,15 +451,13 @@ bool FMenuBar::hotkeyMenu (FKeyEvent*& ev) setSelectedItem(nullptr); redraw(); drop_down = false; - (*iter)->processClicked(); + item->processClicked(); } ev->accept(); return true; } } - - ++iter; } return false; @@ -493,15 +483,10 @@ void FMenuBar::drawItems() setReverse(true); screenWidth = getDesktopWidth(); - auto iter = list.begin(); - auto last = list.end(); std::size_t x{1}; - while ( iter != last ) - { - drawItem (*iter, x); - ++iter; - } + for (auto&& item : list) + drawItem (item, x); // Print spaces to end of line for (; x <= screenWidth; x++) @@ -520,6 +505,7 @@ inline void FMenuBar::drawItem (FMenuItem* menuitem, std::size_t& x) FString txt(menuitem->getText()); std::size_t to_char{}; std::size_t txt_length = txt.getLength(); + std::size_t column_width = getColumnWidth(txt); bool is_enabled = menuitem->isEnabled(); bool is_selected = menuitem->isSelected(); @@ -549,22 +535,24 @@ inline void FMenuBar::drawItem (FMenuItem* menuitem, std::size_t& x) if ( hotkeypos != NOT_SET ) { txt_length--; + column_width--; to_char--; } txtdata.length = to_char; - x += txt_length; + x += column_width; if ( ! is_enabled || is_selected ) txtdata.hotkeypos = NOT_SET; else txtdata.hotkeypos = hotkeypos; + setCursorToHotkeyPosition (menuitem, hotkeypos); drawMenuText (txtdata); drawEllipsis (txtdata, x); drawTrailingSpace (x); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.menu_active_fg, wc.menu_active_bg); if ( isMonochron() && is_enabled && is_selected ) @@ -578,7 +566,7 @@ inline void FMenuBar::setLineAttributes (FMenuItem* menuitem) { bool is_enabled = menuitem->isEnabled(); bool is_selected = menuitem->isSelected(); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( is_enabled ) { @@ -605,6 +593,25 @@ inline void FMenuBar::setLineAttributes (FMenuItem* menuitem) setColor(); } +//---------------------------------------------------------------------- +inline void FMenuBar::setCursorToHotkeyPosition ( FMenuItem* menuitem + , std::size_t hotkeypos ) +{ + if ( ! menuitem->isSelected() ) + return; + + if ( hotkeypos == NOT_SET ) + { + // set cursor to the first character + menuitem->setCursorPos (FPoint(2, 1)); + return; + } + + // set cursor to the hotkey position + std::size_t x = getColumnWidth (menuitem->getText(), hotkeypos); + menuitem->setCursorPos (FPoint(2 + int(x), 1)); +} + //---------------------------------------------------------------------- inline void FMenuBar::drawMenuText (menuText& data) { @@ -615,7 +622,7 @@ inline void FMenuBar::drawMenuText (menuText& data) if ( data.startpos > screenWidth - z ) break; - if ( ! std::iswprint(wint_t(data.text[z])) ) + if ( ! std::iswprint(std::wint_t(data.text[z])) ) { if ( ! isNewFont() && ( int(data.text[z]) < fc::NF_rev_left_arrow2 @@ -627,7 +634,7 @@ inline void FMenuBar::drawMenuText (menuText& data) if ( z == data.hotkeypos ) { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.menu_hotkey_fg, wc.menu_hotkey_bg); if ( ! data.no_underline ) @@ -692,18 +699,15 @@ void FMenuBar::adjustItems() { int item_X = 1; int item_Y = 1; - auto list = getItemList(); - auto iter = list.begin(); - auto last = list.end(); - while ( iter != last ) + for (auto&& item : getItemList()) { // get item width - int item_width = int((*iter)->getWidth()); + int item_width = int(item->getWidth()); - if ( (*iter)->hasMenu() ) + if ( item->hasMenu() ) { - auto menu = (*iter)->getMenu(); + auto menu = item->getMenu(); // set menu position menu->setPos (FPoint(menu->adjustX(item_X), item_Y)); @@ -713,7 +717,6 @@ void FMenuBar::adjustItems() } item_X += item_width; - ++iter; } } @@ -817,30 +820,21 @@ void FMenuBar::mouseDownOverList (const FMouseEvent* ev) return; focus_changed = false; - auto iter = list.begin(); - auto last = list.end(); int mouse_x = ev->getX(); int mouse_y = ev->getY(); - while ( iter != last ) + for (auto&& item : list) { - int x1 = (*iter)->getX(); - int x2 = (*iter)->getX() + int((*iter)->getWidth()); + int x1 = item->getX(); + int x2 = item->getX() + int(item->getWidth()); if ( mouse_y == 1 ) { if ( mouse_x >= x1 && mouse_x < x2 ) - { - // Mouse pointer over item - selectMenuItem (*iter); - } + selectMenuItem (item); // Mouse pointer over item else - { - unselectMenuItem (*iter); - } + unselectMenuItem (item); } - - ++iter; } if ( getStatusBar() ) @@ -866,36 +860,32 @@ void FMenuBar::mouseUpOverList (const FMouseEvent* ev) if ( list.empty() ) return; - auto iter = list.begin(); - auto last = list.end(); int mouse_x = ev->getX(); int mouse_y = ev->getY(); - while ( iter != last ) + for (auto&& item : list) { - int x1 = (*iter)->getX(); - int x2 = (*iter)->getX() + int((*iter)->getWidth()); + int x1 = item->getX(); + int x2 = item->getX() + int(item->getWidth()); if ( mouse_y == 1 && mouse_x >= x1 && mouse_x < x2 - && (*iter)->isEnabled() - && (*iter)->isSelected() ) + && item->isEnabled() + && item->isSelected() ) { // Mouse pointer over item - if ( ! activateMenu(*iter) ) + if ( ! activateMenu(item) ) { - if ( clickItem(*iter) ) + if ( clickItem(item) ) return; } } else { - unselectMenuItem(*iter); + unselectMenuItem(item); redraw(); } - - ++iter; } if ( ! hasSelectedItem() ) @@ -912,32 +902,30 @@ void FMenuBar::mouseMoveOverList (const FMouseEvent* ev) focus_changed = false; bool mouse_over_menubar{false}; - auto iter = list.begin(); - auto last = list.end(); int mouse_x = ev->getX(); int mouse_y = ev->getY(); if ( getTermGeometry().contains(ev->getTermPos()) ) mouse_over_menubar = true; - while ( iter != last ) + for (auto&& item : list) { - int x1 = (*iter)->getX(); - int x2 = (*iter)->getX() + int((*iter)->getWidth()); + int x1 = item->getX(); + int x2 = item->getX() + int(item->getWidth()); if ( mouse_x >= x1 && mouse_x < x2 && mouse_y == 1 ) { // Mouse pointer over item - selectMenuItem(*iter); + selectMenuItem(item); } else { if ( mouse_over_menubar ) { // Unselect selected item without mouse focus - unselectMenuItem(*iter); + unselectMenuItem(item); } else { @@ -945,8 +933,6 @@ void FMenuBar::mouseMoveOverList (const FMouseEvent* ev) passEventToMenu(ev); } } - - ++iter; } if ( getStatusBar() ) diff --git a/src/fmenuitem.cpp b/src/fmenuitem.cpp index ef498a1d..33a4c337 100644 --- a/src/fmenuitem.cpp +++ b/src/fmenuitem.cpp @@ -94,7 +94,7 @@ bool FMenuItem::setEnable (bool enable) if ( super && isMenuBar(super) ) { // Meta + hotkey - super->addAccelerator ( fc::Fmkey_meta + FKey(std::tolower(hotkey)) + super->addAccelerator ( fc::Fmkey_meta + FKey(std::tolower(int(hotkey))) , this ); } } @@ -190,10 +190,14 @@ void FMenuItem::setText (const FString& txt) { text.setString(txt); text_length = text.getLength(); - hotkey = hotKey(); + text_width = getColumnWidth(txt); + hotkey = finalcut::getHotkey(text); if ( hotkey ) + { text_length--; + text_width--; + } updateSuperMenuDimensions(); } @@ -524,12 +528,19 @@ FMenuList* FMenuItem::getFMenuList (FWidget& widget) void FMenuItem::init (FWidget* parent) { text_length = text.getLength(); - hotkey = hotKey(); + text_width = getColumnWidth(text); + hotkey = finalcut::getHotkey(text); + + if ( hotkey > 0xff00 && hotkey < 0xff5f ) // full-width character + hotkey -= 0xfee0; if ( hotkey ) + { text_length--; + text_width--; + } - setGeometry (FPoint(1, 1), FSize(text_length + 2, 1), false); + setGeometry (FPoint(1, 1), FSize(text_width + 2, 1), false); if ( ! parent ) return; @@ -550,7 +561,7 @@ void FMenuItem::init (FWidget* parent) menubar_ptr->calculateDimensions(); if ( hotkey ) // Meta + hotkey - menubar_ptr->addAccelerator ( fc::Fmkey_meta + FKey(std::tolower(hotkey)) + menubar_ptr->addAccelerator ( fc::Fmkey_meta + FKey(std::tolower(int(hotkey))) , this ); addCallback // for this element @@ -566,30 +577,6 @@ void FMenuItem::init (FWidget* parent) } } -//---------------------------------------------------------------------- -uChar FMenuItem::hotKey() -{ - if ( text.isEmpty() ) - return 0; - - std::size_t length = text.getLength(); - - for (std::size_t i{0}; i < length; i++) - { - try - { - if ( i + 1 < length && text[i] == '&' ) - return uChar(text[++i]); - } - catch (const std::out_of_range&) - { - return 0; - } - } - - return 0; -} - //---------------------------------------------------------------------- void FMenuItem::updateSuperMenuDimensions() { diff --git a/src/fmessagebox.cpp b/src/fmessagebox.cpp index ec96fdc3..be1755bb 100644 --- a/src/fmessagebox.cpp +++ b/src/fmessagebox.cpp @@ -61,7 +61,6 @@ FMessageBox::FMessageBox (const FMessageBox& mbox) , headline_text(mbox.headline_text) , text(mbox.text) , text_components(mbox.text_components) - , text_split(mbox.text_split) , max_line_width(mbox.max_line_width) , emphasis_color(mbox.emphasis_color) , num_buttons(mbox.num_buttons) @@ -114,7 +113,6 @@ FMessageBox& FMessageBox::operator = (const FMessageBox& mbox) headline_text = mbox.headline_text; text = mbox.text; text_components = mbox.text_components; - text_split = mbox.text_split; max_line_width = mbox.max_line_width; center_text = mbox.center_text; emphasis_color = mbox.emphasis_color; @@ -139,10 +137,10 @@ void FMessageBox::setHeadline (const FString& headline) for (uInt n{0}; n < num_buttons; n++) button[n]->setY (int(getHeight()) - 4, false); - std::size_t len = headline_text.getLength(); + std::size_t column_width = getColumnWidth(headline_text); - if ( len > max_line_width ) - max_line_width = len; + if ( column_width > max_line_width ) + max_line_width = column_width; } //---------------------------------------------------------------------- @@ -311,9 +309,9 @@ void FMessageBox::calculateDimensions() { FSize size{}; std::size_t headline_height{0}; - text_split = text.split("\n"); + text_components = text.split("\n"); max_line_width = 0; - text_num_lines = uInt(text_split.size()); + text_num_lines = std::size_t(text_components.size()); if ( text_num_lines == 0 ) return; @@ -321,13 +319,12 @@ void FMessageBox::calculateDimensions() if ( ! headline_text.isNull() ) headline_height = 2; - for (uInt i{0}; i < text_num_lines; i++) + for (auto&& line : text_components) { - text_components = &text_split[0]; - std::size_t len = text_components[i].getLength(); + std::size_t column_width = getColumnWidth(line); - if ( len > max_line_width ) - max_line_width = len; + if ( column_width > max_line_width ) + max_line_width = column_width; } size.setHeight (text_num_lines + 8 + headline_height); @@ -344,21 +341,22 @@ void FMessageBox::draw() { FDialog::draw(); - int head_offset = 0; - int center_x = 0; + int y{0}; + int head_offset{0}; + int center_x{0}; // center the whole block int msg_x = int((getWidth() - max_line_width) / 2); if ( isMonochron() ) setReverse(true); - if ( ! headline_text.isNull() ) + if ( ! headline_text.isEmpty() ) { setColor(emphasis_color, getBackgroundColor()); - std::size_t headline_length = headline_text.getLength(); + std::size_t headline_width = getColumnWidth(headline_text); if ( center_text ) // center one line - center_x = int((max_line_width - headline_length) / 2); + center_x = int((max_line_width - headline_width) / 2); print() << FPoint(1 + msg_x + center_x, 4) << headline_text; head_offset = 2; @@ -366,15 +364,16 @@ void FMessageBox::draw() setColor(); - for (int i{0}; i < int(text_num_lines); i++) + for (auto&& line : text_components) { - std::size_t line_length = text_components[i].getLength(); + std::size_t line_width = getColumnWidth(line); if ( center_text ) // center one line - center_x = int((max_line_width - line_length) / 2); + center_x = int((max_line_width - line_width) / 2); - print() << FPoint(1 + msg_x + center_x, 4 + head_offset + i) - << text_components[i]; + print() << FPoint(1 + msg_x + center_x, 4 + head_offset + y) + << line; + y++; } if ( isMonochron() ) diff --git a/src/foptiattr.cpp b/src/foptiattr.cpp index 3bc2048c..98545a8c 100644 --- a/src/foptiattr.cpp +++ b/src/foptiattr.cpp @@ -1220,10 +1220,10 @@ inline bool FOptiAttr::hasColorChanged (charData*& term, charData*& next) { if ( term && next ) { - bool frev = ( on.attr.bit.reverse + bool frev ( ( on.attr.bit.reverse || on.attr.bit.standout || off.attr.bit.reverse - || off.attr.bit.standout ) && fake_reverse; + || off.attr.bit.standout ) && fake_reverse ); return bool ( frev || term->fg_color != next->fg_color || term->bg_color != next->bg_color ); @@ -1483,10 +1483,10 @@ inline void FOptiAttr::change_current_color ( charData*& term auto& Sf = F_set_foreground.cap; auto& Sb = F_set_background.cap; auto& sp = F_set_color_pair.cap; - bool frev = ( off.attr.bit.reverse + bool frev ( ( off.attr.bit.reverse || off.attr.bit.standout || term->attr.bit.reverse - || term->attr.bit.standout ) && fake_reverse; + || term->attr.bit.standout ) && fake_reverse ); if ( AF && AB ) { diff --git a/src/fprogressbar.cpp b/src/fprogressbar.cpp index 8762e229..9e39ff36 100644 --- a/src/fprogressbar.cpp +++ b/src/fprogressbar.cpp @@ -146,7 +146,7 @@ void FProgressbar::drawProgressLabel() , parent_widget->getBackgroundColor() ); else { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor ( wc.dialog_fg, wc.dialog_bg ); } @@ -192,7 +192,7 @@ std::size_t FProgressbar::drawProgressIndicator() double length = double(bar_length * percentage) / 100; auto len = std::size_t(trunc(length)); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); print() << FColorPair (wc.progressbar_fg, wc.progressbar_fg) << FString (len, fc::FullBlock); // █ @@ -225,7 +225,7 @@ void FProgressbar::drawProgressBackground (std::size_t len) // Draw the progress background std::size_t bg_len = bar_length - len; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.progressbar_fg, wc.progressbar_bg); if ( getMaxColor() < 16 ) diff --git a/src/fscrollbar.cpp b/src/fscrollbar.cpp index 4c786922..42afa9b1 100644 --- a/src/fscrollbar.cpp +++ b/src/fscrollbar.cpp @@ -472,7 +472,7 @@ void FScrollbar::draw() //---------------------------------------------------------------------- void FScrollbar::drawVerticalBar() { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.scrollbar_fg, wc.scrollbar_bg); for (int z{1}; z <= slider_pos; z++) @@ -531,7 +531,7 @@ inline void FScrollbar::drawVerticalBackgroundLine() //---------------------------------------------------------------------- void FScrollbar::drawHorizontalBar() { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.scrollbar_fg, wc.scrollbar_bg); if ( isNewFont() ) @@ -577,7 +577,7 @@ inline void FScrollbar::drawHorizontalBackgroundColumn() //---------------------------------------------------------------------- void FScrollbar::drawButtons() { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.scrollbar_button_fg, wc.scrollbar_button_bg); if ( isNewFont() ) diff --git a/src/fscrollview.cpp b/src/fscrollview.cpp index c89e4645..7e482e8d 100644 --- a/src/fscrollview.cpp +++ b/src/fscrollview.cpp @@ -373,8 +373,8 @@ void FScrollView::scrollTo (int x, int y) if ( xoffset > xoffset_end ) xoffset = xoffset_end; - changeX = bool(xoffset_before != xoffset); - changeY = bool(yoffset_before != yoffset); + changeX = bool( xoffset_before != xoffset ); + changeY = bool( yoffset_before != yoffset ); if ( ! isShown() || ! viewport || ! (changeX || changeY) ) return; @@ -764,7 +764,7 @@ void FScrollView::init (FWidget* parent) initScrollbar (vbar, fc::vertical, &FScrollView::cb_VBarChange); initScrollbar (hbar, fc::horizontal, &FScrollView::cb_HBarChange); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.dialog_fg); setBackgroundColor (wc.dialog_bg); setGeometry (FPoint(1, 1), FSize(4, 4)); diff --git a/src/fstartoptions.cpp b/src/fstartoptions.cpp new file mode 100644 index 00000000..d26f235e --- /dev/null +++ b/src/fstartoptions.cpp @@ -0,0 +1,100 @@ +/*********************************************************************** +* fstartoptions.cpp - Contains the start options for initialization * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2019 Markus Gans * +* * +* The 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. * +* * +* The 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 "final/fstartoptions.h" + +namespace finalcut +{ + +// static class attribute +FStartOptions* FStartOptions::start_options{}; + +//---------------------------------------------------------------------- +// class FStartOptions +//---------------------------------------------------------------------- + +// constructors and destructor +//---------------------------------------------------------------------- +FStartOptions::FStartOptions() + : cursor_optimisation{true} + , mouse_support{true} + , terminal_detection{true} + , color_change{true} + , vgafont{false} + , newfont{false} + , encoding{fc::UNKNOWN} +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST) + , meta_sends_escape{true} + , change_cursorstyle{true} +#elif defined(__NetBSD__) || defined(__OpenBSD__) + , meta_sends_escape{true} +#endif +{ } + +//---------------------------------------------------------------------- +FStartOptions::~FStartOptions() // destructor +{ + if ( start_options ) + delete start_options; +} + +// public methods of FStartOptions +//---------------------------------------------------------------------- +FStartOptions& FStartOptions::getFStartOptions() +{ + if ( start_options == 0 ) + { + try + { + start_options = new FStartOptions; + } + catch (const std::bad_alloc& ex) + { + std::cerr << bad_alloc_str << ex.what() << std::endl; + std::abort(); + } + } + + return *start_options; +} + +//---------------------------------------------------------------------- +void FStartOptions::setDefault() +{ + cursor_optimisation = true; + mouse_support = true; + terminal_detection = true; + color_change = true; + vgafont = false; + newfont = false; + encoding = fc::UNKNOWN; + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST) + meta_sends_escape = true; + change_cursorstyle = true; +#elif defined(__NetBSD__) || defined(__OpenBSD__) + meta_sends_escape = true; +#endif +} + +} // namespace finalcut + diff --git a/src/fstatusbar.cpp b/src/fstatusbar.cpp index 9b8740cf..5a3a8918 100644 --- a/src/fstatusbar.cpp +++ b/src/fstatusbar.cpp @@ -175,7 +175,7 @@ bool FStatusBar::hasActivatedKey() void FStatusBar::hide() { FWindow::hide(); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); FColor fg = wc.term_fg; FColor bg = wc.term_bg; setColor (fg, bg); @@ -196,7 +196,7 @@ void FStatusBar::drawMessage() x = x_msg; int space_offset{1}; - bool hasKeys = bool(! key_list.empty()); + bool hasKeys( ! key_list.empty() ); bool isLastActiveFocus{false}; std::size_t termWidth = getDesktopWidth(); @@ -212,7 +212,7 @@ void FStatusBar::drawMessage() if ( isLastActiveFocus ) space_offset = 0; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.statusbar_fg, wc.statusbar_bg); setPrintPos (FPoint(x, 1)); @@ -236,7 +236,7 @@ void FStatusBar::drawMessage() print (' '); } - std::size_t msg_length = getMessage().getLength(); + auto msg_length = getColumnWidth(getMessage()); x += int(msg_length); if ( x - 1 <= int(termWidth) ) @@ -244,8 +244,9 @@ void FStatusBar::drawMessage() else { // Print ellipsis - print ( getMessage().left(msg_length + termWidth - uInt(x) - 1) ); - print (".."); + std::size_t len = msg_length + termWidth - uInt(x) - 1; + print() << getColumnSubString ( getMessage(), 1, len) + << ".."; } } } @@ -358,8 +359,8 @@ void FStatusBar::onMouseDown (FMouseEvent* ev) while ( iter != last ) { int x1 = X - , kname_len = int(getKeyName((*iter)->getKey()).getLength()) - , txt_length = int((*iter)->getText().getLength()) + , kname_len = getKeyNameWidth(*iter) + , txt_length = getKeyTextWidth(*iter) , x2 = x1 + kname_len + txt_length + 1 , mouse_x = ev->getX() , mouse_y = ev->getY(); @@ -401,8 +402,8 @@ void FStatusBar::onMouseUp (FMouseEvent* ev) while ( iter != last ) { int x1 = X - , kname_len = int(getKeyName((*iter)->getKey()).getLength()) - , txt_length = int((*iter)->getText().getLength()) + , kname_len = getKeyNameWidth(*iter) + , txt_length = getKeyTextWidth(*iter) , x2 = x1 + kname_len + txt_length + 1; if ( (*iter)->hasMouseFocus() ) @@ -446,8 +447,8 @@ void FStatusBar::onMouseMove (FMouseEvent* ev) while ( iter != last ) { int x1 = X - , kname_len = int(getKeyName((*iter)->getKey()).getLength()) - , txt_length = int((*iter)->getText().getLength()) + , kname_len = getKeyNameWidth(*iter) + , txt_length = getKeyTextWidth(*iter) , x2 = x1 + kname_len + txt_length + 1 , mouse_x = ev->getX() , mouse_y = ev->getY(); @@ -518,12 +519,26 @@ void FStatusBar::init() if ( getRootWidget() ) getRootWidget()->setBottomPadding(1, true); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.statusbar_fg); setBackgroundColor (wc.statusbar_bg); unsetFocusable(); } +//---------------------------------------------------------------------- +int FStatusBar::getKeyNameWidth (const FStatusKey* key) +{ + const FString& key_name = getKeyName(key->getKey()); + return int(getColumnWidth(key_name)); +} + +//---------------------------------------------------------------------- +int FStatusBar::getKeyTextWidth (const FStatusKey* key) +{ + const FString& key_text = key->getText(); + return int(getColumnWidth(key_text)); +} + //---------------------------------------------------------------------- void FStatusBar::draw() { @@ -549,22 +564,22 @@ void FStatusBar::drawKeys() setReverse(true); auto iter = key_list.begin(); - auto last = key_list.end(); - while ( iter != last ) + while ( iter != key_list.end() ) { - keyname_len = int(getKeyName((*iter)->getKey()).getLength()); + auto item = *iter; + keyname_len = getKeyNameWidth(item); if ( x + keyname_len + 2 < int(screenWidth) ) { - if ( (*iter)->isActivated() || (*iter)->hasMouseFocus() ) + if ( item->isActivated() || item->hasMouseFocus() ) drawActiveKey (iter); else drawKey (iter); } else { - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.statusbar_fg, wc.statusbar_bg); for (; x <= int(screenWidth); x++) @@ -586,7 +601,7 @@ void FStatusBar::drawKey (keyList::const_iterator iter) // Draw not active key auto item = *iter; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.statusbar_hotkey_fg, wc.statusbar_hotkey_bg); x++; print (' '); @@ -595,23 +610,22 @@ void FStatusBar::drawKey (keyList::const_iterator iter) setColor (wc.statusbar_fg, wc.statusbar_bg); x++; print ('-'); - std::size_t txt_length = item->getText().getLength(); - x += int(txt_length); + auto column_width = getColumnWidth (item->getText()); + x += int(column_width); if ( x - 1 <= int(screenWidth) ) print (item->getText()); else { // Print ellipsis - std::size_t len = txt_length + screenWidth - std::size_t(x) - 1; - print (item->getText().left(len)); - print (".."); + std::size_t len = column_width + screenWidth - std::size_t(x) - 1; + print() << getColumnSubString(item->getText(), 1, len) + << ".."; } if ( iter + 1 != key_list.end() && ( (*(iter + 1))->isActivated() || (*(iter + 1))->hasMouseFocus() ) - && x + int(getKeyName((*(iter + 1))->getKey()).getLength()) + 3 - < int(screenWidth) ) + && x + getKeyNameWidth(*(iter + 1)) + 3 < int(screenWidth) ) { // Next element is active if ( isMonochron() ) @@ -649,7 +663,7 @@ void FStatusBar::drawActiveKey (keyList::const_iterator iter) if ( isMonochron() ) setReverse(false); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor ( wc.statusbar_active_hotkey_fg , wc.statusbar_active_hotkey_bg ); x++; @@ -659,8 +673,8 @@ void FStatusBar::drawActiveKey (keyList::const_iterator iter) setColor (wc.statusbar_active_fg, wc.statusbar_active_bg); x++; print ('-'); - std::size_t txt_length = item->getText().getLength(); - x += int(txt_length); + auto column_width = getColumnWidth (item->getText()); + x += int(column_width); if ( x <= int(screenWidth) ) { @@ -671,9 +685,9 @@ void FStatusBar::drawActiveKey (keyList::const_iterator iter) else { // Print ellipsis - print ( item->getText() - .left(txt_length + screenWidth - std::size_t(x) - 1) ); - print (".."); + std::size_t len = column_width + screenWidth - std::size_t(x) - 1; + print() << getColumnSubString(item->getText(), 1, len) + << ".."; } if ( isMonochron() ) diff --git a/src/fstring.cpp b/src/fstring.cpp index 7f5cac65..eefe3dfe 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -20,6 +20,7 @@ * . * ***********************************************************************/ +#include #include #include #include @@ -417,7 +418,7 @@ std::size_t FString::getUTF8length() const if ( ! string ) return 0; - std::size_t len = 0; + std::size_t len{0}; const char* s = c_str(); while ( *s ) @@ -426,27 +427,6 @@ std::size_t FString::getUTF8length() const return len; } -//---------------------------------------------------------------------- -FString& FString::sprintf (const FString format, ...) -{ - static constexpr int BUFSIZE = 4096; - wchar_t buffer[BUFSIZE]{}; - va_list args{}; - - if ( ! format ) - { - clear(); - return *this; - } - - va_start (args, format); - std::vswprintf (buffer, BUFSIZE, format.wc_str(), args); - va_end (args); - - _assign (buffer); - return *this; -} - //---------------------------------------------------------------------- FString FString::clear() { @@ -511,17 +491,11 @@ const std::string FString::toString() const FString FString::toLower() const { FString s(string); - wchar_t* p = s.string; - - if ( p ) - { - while ( *p ) - { - *p = wchar_t(std::towlower(wint_t(*p))); - p++; - } - } - + auto to_lower = [] (wchar_t& c) + { + c = wchar_t(std::towlower(std::wint_t(c))); + }; + std::for_each (s.begin(), s.end(), to_lower); return s; } @@ -529,17 +503,11 @@ FString FString::toLower() const FString FString::toUpper() const { FString s(string); - wchar_t* p = s.string; - - if ( p ) - { - while ( *p ) - { - *p = wchar_t(std::towupper(wint_t(*p))); - p++; - } - } - + auto to_upper = [] (wchar_t& c) + { + c = wchar_t(std::towupper(std::wint_t(c))); + }; + std::for_each (s.begin(), s.end(), to_upper); return s; } @@ -621,9 +589,9 @@ long FString::toLong() const p++; } - while ( std::iswdigit(wint_t(*p)) ) + while ( std::iswdigit(std::wint_t(*p)) ) { - uChar d = uChar((*p) - L'0'); + uChar d = uChar(*p - L'0'); if ( num > tenth_limit || (num == tenth_limit && d > tenth_limit_digit) ) @@ -638,7 +606,7 @@ long FString::toLong() const p++; } - if ( *p != L'\0' && ! std::iswdigit(wint_t(*p)) ) + if ( *p != L'\0' && ! std::iswdigit(std::wint_t(*p)) ) throw std::invalid_argument ("no valid number"); if ( neg ) @@ -671,9 +639,9 @@ uLong FString::toULong() const p++; } - while ( std::iswdigit(wint_t(*p)) ) + while ( std::iswdigit(std::wint_t(*p)) ) { - uChar d = uChar((*p) - L'0'); + uChar d = uChar(*p - L'0'); if ( num > tenth_limit || (num == tenth_limit && d > tenth_limit_digit) ) @@ -685,7 +653,7 @@ uLong FString::toULong() const p++; } - if ( *p != L'\0' && ! std::iswdigit(wint_t(*p)) ) + if ( *p != L'\0' && ! std::iswdigit(std::wint_t(*p)) ) throw std::invalid_argument ("no valid number"); return num; @@ -743,7 +711,7 @@ FString FString::ltrim() const const wchar_t* p = s.string; - while ( std::iswspace(wint_t(*p)) ) + while ( std::iswspace(std::wint_t(*p)) ) p++; return FString(p); @@ -761,10 +729,10 @@ FString FString::rtrim() const wchar_t* p = s.string; wchar_t* last = p + length; - while ( std::iswspace(wint_t(*--last)) && last > p ) + while ( std::iswspace(std::wint_t(*--last)) && last > p ) s.length--; - if ( last == p && std::iswspace(wint_t(*last)) ) + if ( last == p && std::iswspace(std::wint_t(*last)) ) s = L""; else *(last + 1) = '\0'; @@ -1166,29 +1134,23 @@ FString FString::replace (const FString& from, const FString& to) FString FString::replaceControlCodes() const { FString s(string); - wchar_t* p = s.string; - if ( p ) + for (auto&& c : s) { - while ( *p ) + if ( c <= L'\x1f' ) { - if ( *p <= L'\x1f' ) - { - *p += L'\x2400'; - } - else if ( *p == L'\x7f' ) - { - *p = L'\x2421'; - } - else if ( *p >= L'\x80' && *p <= L'\x9f' ) - { - *p = L' '; - } - else if ( ! std::iswprint(wint_t(*p)) ) - *p = L' '; - - p++; + c += L'\x2400'; } + else if ( c == L'\x7f' ) + { + c = L'\x2421'; + } + else if ( c >= L'\x80' && c <= L'\x9f' ) + { + c = L' '; + } + else if ( ! std::iswprint(std::wint_t(c)) ) + c = L' '; } return s; @@ -1224,36 +1186,28 @@ FString FString::expandTabs (int tabstop) const FString FString::removeDel() const { FString s(string); - const wchar_t* p = s.string; + std::size_t i{0}; + std::size_t count{0}; - if ( p ) + for (auto&& c : s) { - uInt i{0}; - uInt d{0}; - - while ( *p ) + if ( c == 0x7f ) { - if ( *p == 0x7f ) - { - d++; - } - else if ( d > 0 ) - { - d--; - } - else - { - s.string[i] = *p; - i++; - } - - p++; + count++; + } + else if ( count > 0 ) + { + count--; + } + else // count == 0 + { + s.string[i] = c; + i++; } - - s.string[i] = L'\0'; - s.length = i; } + s.string[i] = L'\0'; + s.length = i; return s; } @@ -1262,31 +1216,23 @@ FString FString::removeDel() const FString FString::removeBackspaces() const { FString s(string); - const wchar_t* p = s.string; + std::size_t i{0}; - if ( p ) + for (auto&& c : s) { - uInt i = 0; - - while ( *p ) + if ( c != L'\b' ) { - if ( *p != L'\b' ) - { - s.string[i] = *p; - i++; - } - else if ( i > 0 ) - { - i--; - } - - p++; + s.string[i] = c; + i++; + } + else if ( i > 0 ) + { + i--; } - - s.string[i] = L'\0'; - s.length = i; } + s.string[i] = L'\0'; + s.length = i; return s; } @@ -1367,7 +1313,7 @@ inline void FString::initLength (std::size_t len) } //---------------------------------------------------------------------- -inline void FString::_assign (const wchar_t s[]) +void FString::_assign (const wchar_t s[]) { if ( ! s ) { @@ -1378,7 +1324,7 @@ inline void FString::_assign (const wchar_t s[]) if ( string && std::wcscmp(string, s) == 0 ) return; // string == s - uInt new_length = uInt(std::wcslen(s)); + uInt new_length= uInt(std::wcslen(s)); if ( ! string || new_length > capacity() ) { @@ -1404,7 +1350,7 @@ inline void FString::_assign (const wchar_t s[]) } //---------------------------------------------------------------------- -inline void FString::_insert (std::size_t len, const wchar_t s[]) +void FString::_insert (std::size_t len, const wchar_t s[]) { if ( len == 0 ) // String s is a null or a empty string return; @@ -1430,9 +1376,9 @@ inline void FString::_insert (std::size_t len, const wchar_t s[]) } //---------------------------------------------------------------------- -inline void FString::_insert ( std::size_t pos - , std::size_t len - , const wchar_t s[] ) +void FString::_insert ( std::size_t pos + , std::size_t len + , const wchar_t s[] ) { if ( len == 0 ) // String s is a null or a empty string return; @@ -1491,7 +1437,7 @@ inline void FString::_insert ( std::size_t pos } //---------------------------------------------------------------------- -inline void FString::_remove (std::size_t pos, std::size_t len) +void FString::_remove (std::size_t pos, std::size_t len) { if ( capacity() - length + len <= FWDBUFFER ) { @@ -1558,7 +1504,7 @@ inline char* FString::wc_to_c_str (const wchar_t s[]) const int size = int(std::wcslen(s)) + 1; int dest_size = size * int(CHAR_SIZE); const wchar_t* src = s; - std::mbstate_t state; + std::mbstate_t state{}; std::memset (&state, '\0', sizeof(mbstate_t)); try @@ -1611,7 +1557,7 @@ inline wchar_t* FString::c_to_wc_str (const char s[]) const int dest_size = size * int(CHAR_SIZE); const char* src = s; wchar_t* dest{}; - std::mbstate_t state; + std::mbstate_t state{}; std::memset (&state, '\0', sizeof(mbstate_t)); try diff --git a/src/fswitch.cpp b/src/fswitch.cpp index 147e009e..4ebcacb4 100644 --- a/src/fswitch.cpp +++ b/src/fswitch.cpp @@ -143,7 +143,7 @@ inline void FSwitch::drawChecked() { wchar_t on[6]{L" On "}; wchar_t off[6]{L" Off "}; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( hasFocus() && ! button_pressed ) { @@ -194,7 +194,7 @@ inline void FSwitch::drawUnchecked() wchar_t on[6]{L" On "}; wchar_t off[6]{L" Off "}; - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setColor (wc.button_inactive_fg, wc.button_inactive_bg); if ( isMonochron() ) diff --git a/src/fterm.cpp b/src/fterm.cpp index 08203f08..c29da34d 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -35,9 +35,9 @@ #include "final/foptimove.h" #include "final/fstartoptions.h" #include "final/fstring.h" -#include "final/fsystem.h" #include "final/fsystemimpl.h" #include "final/fterm.h" +#include "final/ftermbuffer.h" #include "final/ftermcap.h" #include "final/ftermcapquirks.h" #include "final/ftermdata.h" @@ -1165,49 +1165,11 @@ wchar_t FTerm::charEncode (wchar_t c, fc::encoding enc) } if ( enc == fc::PC && ch_enc == c ) - ch_enc = FTerm::unicode_to_cp437(c); + ch_enc = finalcut::unicode_to_cp437(c); return ch_enc; } -//---------------------------------------------------------------------- -wchar_t FTerm::cp437_to_unicode (uChar c) -{ - constexpr std::size_t CP437 = 0; - constexpr std::size_t UNICODE = 1; - wchar_t ucs = wchar_t(c); - - for (std::size_t i{0}; i <= fc::lastCP437Item; i++) - { - if ( fc::cp437_to_ucs[i][CP437] == c ) // found - { - ucs = fc::cp437_to_ucs[UNICODE][1]; - break; - } - } - - return ucs; -} - -//---------------------------------------------------------------------- -uChar FTerm::unicode_to_cp437 (wchar_t ucs) -{ - constexpr std::size_t CP437 = 0; - constexpr std::size_t UNICODE = 1; - uChar c = '?'; - - for (std::size_t i{0}; i <= fc::lastCP437Item; i++) - { - if ( fc::cp437_to_ucs[i][UNICODE] == ucs ) // found - { - c = uChar(fc::cp437_to_ucs[i][CP437]); - break; - } - } - - return c; -} - //---------------------------------------------------------------------- bool FTerm::scrollTermForward() { @@ -1234,21 +1196,6 @@ bool FTerm::scrollTermReverse() return false; } -//---------------------------------------------------------------------- -void FTerm::putstringf (const char format[], ...) -{ - assert ( format != 0 ); - char buf[512]{}; - va_list args{}; - - char* str = buf; - va_start (args, format); - vsnprintf (str, sizeof(buf), format, args); - va_end (args); - - fsys->tputs (str, 1, FTerm::putchar_ASCII); -} - //---------------------------------------------------------------------- void FTerm::putstring (const char str[], int affcnt) { @@ -1352,6 +1299,12 @@ void FTerm::exitWithMessage (const FString& message) // private methods of FTerm +//---------------------------------------------------------------------- +inline FStartOptions& FTerm::getStartOptions() +{ + return FStartOptions::getFStartOptions(); +} + //---------------------------------------------------------------------- void FTerm::init_global_values (bool disable_alt_screen) { @@ -1441,7 +1394,7 @@ void FTerm::init_alt_charset() uChar keyChar = uChar(fc::vt100_key_to_utf8[n][vt100_key]); uChar altChar = uChar(vt100_alt_char[keyChar]); uInt utf8char = uInt(fc::vt100_key_to_utf8[n][utf8_char]); - fc::encoding num = fc::NUM_OF_ENCODINGS; + fc::encoding num{fc::NUM_OF_ENCODINGS}; uInt* p = std::find ( fc::character[0] , fc::character[fc::lastCharItem] + num @@ -2575,4 +2528,232 @@ uInt env2uint (const char* env) } } +//---------------------------------------------------------------------- +wchar_t cp437_to_unicode (uChar c) +{ + constexpr std::size_t CP437 = 0; + constexpr std::size_t UNICODE = 1; + wchar_t ucs(c); + + for (std::size_t i{0}; i <= fc::lastCP437Item; i++) + { + if ( fc::cp437_to_ucs[i][CP437] == c ) // found + { + ucs = fc::cp437_to_ucs[i][UNICODE]; + break; + } + } + + return ucs; +} + +//---------------------------------------------------------------------- +uChar unicode_to_cp437 (wchar_t ucs) +{ + constexpr std::size_t CP437 = 0; + constexpr std::size_t UNICODE = 1; + uChar c{'?'}; + + for (std::size_t i{0}; i <= fc::lastCP437Item; i++) + { + if ( fc::cp437_to_ucs[i][UNICODE] == ucs ) // found + { + c = uChar(fc::cp437_to_ucs[i][CP437]); + break; + } + } + + return c; +} + +//---------------------------------------------------------------------- +FString getFullWidth (const FString& str) +{ + // Converts half-width to full-width characters + + FString s(str); + constexpr std::size_t HALF = 0; + constexpr std::size_t FULL = 1; + + for (auto&& c : s) + { + if ( c > L'\x20' && c < L'\x7f' ) // half-width ASCII + { + c += 0xfee0; + } + else for (std::size_t i{0}; i <= fc::lastHalfWidthItem; i++) + { + if ( fc::halfWidth_fullWidth[i][HALF] == c ) // found + { + c = fc::halfWidth_fullWidth[i][FULL]; + } + } + } + + return s; +} + +//---------------------------------------------------------------------- +FString getHalfWidth (const FString& str) +{ + // Converts full-width to half-width characters + + FString s(str); + constexpr std::size_t HALF = 0; + constexpr std::size_t FULL = 1; + + for (auto&& c : s) + { + if ( c > L'\xff00' && c < L'\xff5f' ) // full-width ASCII + { + c -= 0xfee0; + } + else for (std::size_t i{0}; i <= fc::lastHalfWidthItem; i++) + { + if ( fc::halfWidth_fullWidth[i][FULL] == c ) // found + { + c = fc::halfWidth_fullWidth[i][HALF]; + } + } + } + + return s; +} + +//---------------------------------------------------------------------- +std::size_t getColumnWidthToLength ( const FString& str + , std::size_t col_len ) +{ + std::size_t column_width{0}, length{0}; + + for (auto&& ch : str) + { + if ( column_width < col_len ) + { + column_width += getColumnWidth(ch); + length++; + } + } + + return length; +} + +//---------------------------------------------------------------------- +FString getColumnSubString ( const FString& str + , std::size_t col_pos, std::size_t col_len ) +{ + FString s(str); + std::size_t col_first{1}, col_num{0}, first{1}, num{0}; + + if ( col_len == 0 || s.isEmpty() ) + return FString(L""); + + if ( col_pos == 0 ) + col_pos = 1; + + for (auto&& ch : s) + { + std::size_t width = getColumnWidth(ch); + + if ( col_first < col_pos ) + { + if ( col_first + width <= col_pos ) + { + col_first += width; + first++; + } + else + { + ch = fc::SingleLeftAngleQuotationMark; // ‹ + num = col_num = 1; + col_pos = col_first; + } + } + else + { + if ( col_num + width <= col_len ) + { + col_num += width; + num++; + } + else if ( col_num < col_len ) + { + ch = fc::SingleRightAngleQuotationMark; // › + num++; + break; + } + } + } + + if ( col_first < col_pos ) // String length < col_pos + return FString(L""); + + return s.mid(first, num); +} + +//---------------------------------------------------------------------- +std::size_t getColumnWidth (const FString& s, std::size_t pos) +{ + if ( s.isEmpty() ) + return 0; + + std::size_t column_width{0}; + auto length = s.getLength(); + + if ( pos > length ) + pos = length; + + for (std::size_t i{0}; i < pos; i++) + column_width += getColumnWidth(s[i]); + + return column_width; +} + +//---------------------------------------------------------------------- +std::size_t getColumnWidth (const FString& s) +{ + if ( s.isEmpty() ) + return 0; + + const wchar_t* str = s.wc_str(); + size_t len = std::wcslen(str); + int column_width = wcswidth (str, len); + return ( column_width == -1 ) ? 0 : std::size_t(column_width); +} + +//---------------------------------------------------------------------- +std::size_t getColumnWidth (const wchar_t wchar) +{ + int column_width = wcwidth (wchar); + return ( column_width == -1 ) ? 0 : std::size_t(column_width); +} + +//---------------------------------------------------------------------- +std::size_t getColumnWidth (charData& term_char) +{ + int column_width = wcwidth (term_char.code); + std::size_t char_width = ( column_width == -1 ) ? 0 : std::size_t(column_width); + + if ( char_width == 2 && FTerm::getEncoding() != fc::UTF8 ) + { + term_char.code = '.'; + term_char.attr.bit.char_width = 1; + } + else + term_char.attr.bit.char_width = char_width & 0x03; + + return char_width; +} + +//---------------------------------------------------------------------- +std::size_t getColumnWidth (const FTermBuffer& termbuffer) +{ + std::size_t column_width{0}; + + for (auto&& tc : termbuffer) + column_width += tc.attr.bit.char_width; + + return column_width; +} + } // namespace finalcut diff --git a/src/ftermbuffer.cpp b/src/ftermbuffer.cpp index 90206722..bcbc0ce3 100644 --- a/src/ftermbuffer.cpp +++ b/src/ftermbuffer.cpp @@ -41,55 +41,43 @@ FTermBuffer::~FTermBuffer() // destructor // public methods of FTermBuffer //---------------------------------------------------------------------- -int FTermBuffer::writef (const FString format, ...) +const FString FTermBuffer::toString() const { - static constexpr int BUFSIZE = 4096; - wchar_t buffer[BUFSIZE]{}; - va_list args{}; + std::wstring wide_string{}; + wide_string.reserve(data.size()); - if ( format.isEmpty() ) - return 0; + for (auto&& tc : data) + wide_string.push_back(tc.code); - va_start (args, format); - std::vswprintf (buffer, BUFSIZE, format.wc_str(), args); - va_end (args); - - FString str(buffer); - return write(str); + return FString(wide_string); } //---------------------------------------------------------------------- -int FTermBuffer::write (const FString& s) +int FTermBuffer::write (const FString& string) { - assert ( ! s.isNull() ); - int len{0}; - const wchar_t* p = s.wc_str(); + assert ( ! string.isNull() ); + int len = int(string.getLength()); - if ( p ) + for (auto&& c : string) { - while ( *p ) - { - charData nc; // next character - nc = FVTerm::getAttribute(); - nc.code = *p; - nc.attr.bit.no_changes = false; - nc.attr.bit.printed = false; - - data.push_back(nc); - - p++; - len++; - } // end of while + charData nc; // next character + nc = FVTerm::getAttribute(); + nc.code = c; + getColumnWidth(nc); // add column width + nc.attr.bit.no_changes = false; + nc.attr.bit.printed = false; + data.push_back(nc); } return len; } //---------------------------------------------------------------------- -int FTermBuffer::write (wchar_t c) +int FTermBuffer::write (wchar_t ch) { charData nc = FVTerm::getAttribute(); // next character - nc.code = c; + nc.code = ch; + getColumnWidth(nc); // add column width nc.attr.bit.no_changes = false; nc.attr.bit.printed = false; diff --git a/src/ftermfreebsd.cpp b/src/ftermfreebsd.cpp index 3143ea7b..00acd0e8 100644 --- a/src/ftermfreebsd.cpp +++ b/src/ftermfreebsd.cpp @@ -193,7 +193,7 @@ bool FTermFreeBSD::saveFreeBSDAltKey() return false; // Save current mapping - bsd_alt_keymap = keymap.key[left_alt].map[0]; + bsd_alt_keymap = uInt(keymap.key[left_alt].map[0]); return true; } @@ -213,7 +213,7 @@ bool FTermFreeBSD::setFreeBSDAltKey (uInt key) return false; // Mapping "key" on the left alt key - keymap.key[left_alt].map[0] = key; + keymap.key[left_alt].map[0] = int(key); if ( (keymap.n_keys > 0) && fsystem && (fsystem->ioctl(0, PIO_KEYMAP, &keymap) < 0) ) diff --git a/src/ftermlinux.cpp b/src/ftermlinux.cpp index 3f67e1b4..7d0ed3f2 100644 --- a/src/ftermlinux.cpp +++ b/src/ftermlinux.cpp @@ -358,7 +358,7 @@ bool FTermLinux::loadNewFont() //---------------------------------------------------------------------- bool FTermLinux::loadOldFont() { - bool retval = false; + bool retval{false}; if ( FTerm::openConsole() == 0 ) { diff --git a/src/ftermopenbsd.cpp b/src/ftermopenbsd.cpp index 986d943f..aaaab8fc 100644 --- a/src/ftermopenbsd.cpp +++ b/src/ftermopenbsd.cpp @@ -104,8 +104,8 @@ bool FTermOpenBSD::setBeep (int Hz, int ms) wskbd_bell_data bell; bell.which = WSKBD_BELL_DOALL; - bell.pitch = Hz; - bell.period = ms; + bell.pitch = uInt(Hz); + bell.period = uInt(ms); bell.volume = 50; // 50% volume if ( fsystem && fsystem->ioctl(0, WSKBDIO_SETBELL, &bell) < 0 ) diff --git a/src/ftermxterminal.cpp b/src/ftermxterminal.cpp index 3d9ff2c4..d31a3eee 100644 --- a/src/ftermxterminal.cpp +++ b/src/ftermxterminal.cpp @@ -398,6 +398,7 @@ void FTermXTerminal::setXTermCursorStyle() if ( TCAP(fc::t_cursor_style) || term_detection->isXTerminal() + || term_detection->isCygwinTerminal() || term_detection->isMinttyTerm() || term_detection->hasSetCursorStyleSupport() ) { @@ -413,6 +414,7 @@ void FTermXTerminal::setXTermTitle() if ( term_detection->isXTerminal() || term_detection->isScreenTerm() + || term_detection->isCygwinTerminal() || term_detection->isMinttyTerm() || term_detection->isPuttyTerminal() || FTermcap::osc_support ) @@ -626,12 +628,12 @@ void FTermXTerminal::resetXTermColorMap() if ( term_detection->isMinttyTerm() ) { - FTerm::putstringf (ESC "c"); // Full Reset (RIS) + FTerm::putstring (ESC "c"); // Full Reset (RIS) } else if ( canResetColor() ) { oscPrefix(); - FTerm::putstringf (OSC "104" BEL); + FTerm::putstring (OSC "104" BEL); oscPostfix(); std::fflush(stdout); } @@ -715,7 +717,7 @@ void FTermXTerminal::resetXTermHighlightBackground() if ( canResetColor() ) { oscPrefix(); - FTerm::putstringf (OSC "117" BEL); + FTerm::putstring (OSC "117" BEL); oscPostfix(); std::fflush(stdout); } diff --git a/src/ftextview.cpp b/src/ftextview.cpp index fe869087..734f0c20 100644 --- a/src/ftextview.cpp +++ b/src/ftextview.cpp @@ -145,8 +145,8 @@ void FTextView::scrollBy (int dx, int dy) //---------------------------------------------------------------------- void FTextView::scrollTo (int x, int y) { - bool changeX = bool(x != xoffset); - bool changeY = bool(y != yoffset); + bool changeX( x != xoffset ); + bool changeY( y != yoffset ); if ( ! isShown() || ! (changeX || changeY) ) return; @@ -207,7 +207,7 @@ void FTextView::append (const FString& str) //---------------------------------------------------------------------- void FTextView::insert (const FString& str, int pos) { - FString s; + FString s{}; if ( pos < 0 || pos >= int(getRows()) ) pos = int(getRows()); @@ -217,23 +217,22 @@ void FTextView::insert (const FString& str, int pos) else s = FString(str).rtrim().expandTabs(getTabstop()); - auto iter = data.begin(); + auto text_split = s.split("\r\n"); - auto num = text_split.size(); - for (std::size_t i{0}; i < num; i++) + for (auto&& line : text_split) // Line loop { - text_split[i] = text_split[i].removeBackspaces() - .removeDel() - .replaceControlCodes() - .rtrim(); - auto len = text_split[i].getLength(); + line = line.removeBackspaces() + .removeDel() + .replaceControlCodes() + .rtrim(); + auto column_width = getColumnWidth(line); - if ( len > maxLineWidth ) + if ( column_width > maxLineWidth ) { - maxLineWidth = len; + maxLineWidth = column_width; - if ( len > getTextWidth() ) + if ( column_width > getTextWidth() ) { int hmax = ( maxLineWidth > getTextWidth() ) ? int(maxLineWidth) - int(getTextWidth()) @@ -242,12 +241,13 @@ void FTextView::insert (const FString& str, int pos) hbar->setPageSize (int(maxLineWidth), int(getTextWidth())); hbar->calculateSliderValues(); - if ( ! hbar->isShown() ) + if ( isShown() && ! hbar->isShown() ) hbar->show(); } } } + auto iter = data.begin(); data.insert (iter + pos, text_split.begin(), text_split.end()); int vmax = ( getRows() > getTextHeight() ) ? int(getRows()) - int(getTextHeight()) @@ -256,10 +256,10 @@ void FTextView::insert (const FString& str, int pos) vbar->setPageSize (int(getRows()), int(getTextHeight())); vbar->calculateSliderValues(); - if ( ! vbar->isShown() && getRows() > getTextHeight() ) + if ( isShown() && ! vbar->isShown() && getRows() > getTextHeight() ) vbar->show(); - if ( vbar->isShown() && getRows() <= getTextHeight() ) + if ( isShown() && vbar->isShown() && getRows() <= getTextHeight() ) vbar->hide(); processChanged(); @@ -597,7 +597,7 @@ void FTextView::init() { initScrollbar (vbar, fc::vertical, &FTextView::cb_VBarChange); initScrollbar (hbar, fc::horizontal, &FTextView::cb_HBarChange); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.dialog_fg); setBackgroundColor (wc.dialog_bg); nf_offset = isNewFont() ? 1 : 0; @@ -662,6 +662,12 @@ void FTextView::draw() if ( isMonochron() ) setReverse(false); + if ( ! isShown() ) // first drawing + { + vbar->show(); + hbar->show(); + } + if ( vbar->isShown() ) vbar->redraw(); @@ -703,40 +709,48 @@ void FTextView::drawText() if ( isMonochron() ) setReverse(true); - for (std::size_t y{0}; y < num; y++) + for (std::size_t y{0}; y < num; y++) // Line loop { - std::size_t i{}; - std::size_t n = y + std::size_t(yoffset); - std::size_t x = std::size_t(xoffset) + 1; - FString line(data[n].mid (x, getTextWidth())); - const auto line_str = line.wc_str(); - const auto len = line.getLength(); + std::size_t n = std::size_t(yoffset) + y; + std::size_t pos = std::size_t(xoffset) + 1; + std::size_t trailing_whitespace{0}; + auto text_width = getTextWidth(); + FString line(getColumnSubString(data[n], pos, text_width)); + auto column_width = getColumnWidth(line); print() << FPoint(2, 2 - nf_offset + int(y)); - for (i = 0; i < len; i++) + for (auto&& ch : line) // Column loop { - wchar_t ch = line_str[i]; - bool utf8 = ( getEncoding() == fc::UTF8 ) ? true : false; - - // only printable and 1 column per character - if ( ( (utf8 && std::iswprint(wint_t(ch))) - || (!utf8 && std::isprint(ch)) ) - && wcwidth(ch) == 1 ) - { + if ( isPrintable(ch) ) print (ch); - } else print ('.'); } - for (; i < getTextWidth(); i++) - print (' '); + if ( column_width <= text_width ) + trailing_whitespace = text_width - column_width; + + print() << FString(trailing_whitespace, L' '); } if ( isMonochron() ) setReverse(false); } +//---------------------------------------------------------------------- +inline bool FTextView::isPrintable (wchar_t ch) +{ + // Check for printable characters + + bool utf8 = ( getEncoding() == fc::UTF8 ) ? true : false; + + if ( (utf8 && std::iswprint(std::wint_t(ch))) + || (!utf8 && std::isprint(ch)) ) + return true; + + return false; +} + //---------------------------------------------------------------------- void FTextView::processChanged() { diff --git a/src/ftogglebutton.cpp b/src/ftogglebutton.cpp index da691cc8..11993501 100644 --- a/src/ftogglebutton.cpp +++ b/src/ftogglebutton.cpp @@ -86,7 +86,8 @@ void FToggleButton::setGeometry ( const FPoint& pos, const FSize& s FSize size(s); std::size_t hotkey_mark = ( getHotkey(text) ) ? 1 : 0; - std::size_t min_width = button_width + text.getLength() - hotkey_mark; + std::size_t column_width = getColumnWidth(text); + std::size_t min_width = button_width + column_width - hotkey_mark; if ( size.getWidth() < min_width ) size.setWidth(min_width); @@ -109,7 +110,7 @@ bool FToggleButton::setNoUnderline (bool enable) bool FToggleButton::setEnable (bool enable) { FWidget::setEnable(enable); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( enable ) { @@ -140,7 +141,7 @@ bool FToggleButton::setEnable (bool enable) bool FToggleButton::setFocus (bool enable) { FWidget::setFocus(enable); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( enable ) { @@ -194,8 +195,8 @@ void FToggleButton::setText (const FString& txt) { text.setString(txt); std::size_t hotkey_mark = ( getHotkey(text) ) ? 1 : 0; - - setWidth(button_width + text.getLength() - hotkey_mark); + std::size_t column_width = getColumnWidth(text); + setWidth(button_width + column_width - hotkey_mark); if ( isEnabled() ) { @@ -371,6 +372,9 @@ void FToggleButton::setHotkeyAccelerator() { FKey hotkey = getHotkey(text); + if ( hotkey > 0xff00 && hotkey < 0xff5f ) // full-width character + hotkey -= 0xfee0; + if ( hotkey ) { if ( std::isalpha(int(hotkey)) || std::isdigit(int(hotkey)) ) @@ -534,7 +538,7 @@ void FToggleButton::setGroup (FButtonGroup* btngroup) void FToggleButton::init() { setGeometry (FPoint(1, 1), FSize(4, 1), false); // initialize geometry values - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( isEnabled() ) { @@ -564,7 +568,7 @@ void FToggleButton::drawText ( wchar_t LabelText[] if ( isMonochron() ) setReverse(true); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); if ( isEnabled() ) setColor (wc.label_fg, wc.label_bg); diff --git a/src/ftooltip.cpp b/src/ftooltip.cpp index 5700cd55..3548616f 100644 --- a/src/ftooltip.cpp +++ b/src/ftooltip.cpp @@ -78,6 +78,7 @@ void FToolTip::setText (const FString& txt) //---------------------------------------------------------------------- void FToolTip::draw() { + int y{0}; setColor(); if ( getMaxColor() < 16 ) @@ -86,9 +87,10 @@ void FToolTip::draw() clearArea(); drawBorder(); - for (std::size_t i{0}; i < text_num_lines; i++) + for (auto&& line : text_components) { - print() << FPoint(3, 2 + int(i)) << text_components[i]; + print() << FPoint(3, 2 + y) << line; + y++; } unsetBold(); @@ -126,7 +128,7 @@ void FToolTip::init() // initialize geometry values setGeometry (FPoint(1, 1), FSize(3, 3), false); setMinimumSize (FSize(3, 3)); - const FWidgetColors& wc = getFWidgetColors(); + const auto& wc = getFWidgetColors(); setForegroundColor (wc.tooltip_fg); setBackgroundColor (wc.tooltip_bg); calculateDimensions(); @@ -138,19 +140,18 @@ void FToolTip::calculateDimensions() int x{}, y{}; auto r = getRootWidget(); max_line_width = 0; - text_split = text.split("\n"); - text_num_lines = uInt(text_split.size()); + text_components = text.split("\n"); + text_num_lines = std::size_t(text_components.size()); if ( text_num_lines == 0 ) return; - for (std::size_t i{0}; i < text_num_lines; i++) + for (auto&& line : text_components) { - text_components = &text_split[0]; - std::size_t len = text_components[i].getLength(); + std::size_t column_width = getColumnWidth(line); - if ( len > max_line_width ) - max_line_width = len; + if ( column_width > max_line_width ) + max_line_width = column_width; } std::size_t h = text_num_lines + 2; diff --git a/src/fvterm.cpp b/src/fvterm.cpp index be7886db..60ad3a1e 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -323,24 +323,6 @@ void FVTerm::delPreprocessingHandler (FVTerm* instance) } } -//---------------------------------------------------------------------- -int FVTerm::printf (const FString format, ...) -{ - static constexpr int BUFSIZE = 4096; - wchar_t buffer[BUFSIZE]{}; - va_list args{}; - - if ( format.isEmpty() ) - return 0; - - va_start (args, format); - std::vswprintf (buffer, BUFSIZE, format.wc_str(), args); - va_end (args); - - FString str(buffer); - return print(str); -} - //---------------------------------------------------------------------- int FVTerm::print (const FString& s) { @@ -532,6 +514,10 @@ int FVTerm::print (term_area* area, charData& term_char) int bsh = area->bottom_shadow; int ax = area->cursor_x - 1; int ay = area->cursor_y - 1; + std::size_t char_width = getColumnWidth(nc); // add column width + + if ( char_width == 0 && ! nc.attr.bit.fullwidth_padding ) + return 0; if ( area->cursor_x > 0 && area->cursor_y > 0 @@ -579,6 +565,8 @@ int FVTerm::print (term_area* area, charData& term_char) area->cursor_x = 1; area->cursor_y++; } + else if ( char_width == 2 ) + printPaddingCharacter (area, nc); // Prevent up scrolling if ( area->cursor_y > height + bsh ) @@ -658,10 +646,10 @@ void FVTerm::resizeArea ( const FRect& box int offset_left = box.getX(); int offset_top = box.getY(); - int width = int(box.getWidth()); - int height = int(box.getHeight()); - int rsw = int(shadow.getWidth()); - int bsh = int(shadow.getHeight()); + int width = int(box.getWidth()); + int height = int(box.getHeight()); + int rsw = int(shadow.getWidth()); + int bsh = int(shadow.getHeight()); assert ( offset_top >= 0 ); assert ( width > 0 && width + rsw > 0 ); @@ -872,7 +860,7 @@ FVTerm::covered_state FVTerm::isCovered ( const FPoint& pos if ( ! area ) return non_covered; - bool found = bool(area == vdesktop); + bool found( area == vdesktop ); auto is_covered = non_covered; if ( FWidget::getWindowList() && ! FWidget::getWindowList()->empty() ) @@ -1190,8 +1178,8 @@ void FVTerm::updateVTerm (term_area* area) int ay = area->offset_top; int width = area->width + area->right_shadow; int height = area->height + area->bottom_shadow; - int ol = 0; // Outside left - int y_end; + int ol{0}; // Outside left + int y_end{}; // Call the processing handler methods callPreprocessingHandler(area); @@ -1209,8 +1197,7 @@ void FVTerm::updateVTerm (term_area* area) for (int y{0}; y < y_end; y++) // Line loop { - int _xmin, _xmax; - bool modified = false; + bool modified{false}; int line_xmin = int(area->changes[y].xmin); int line_xmax = int(area->changes[y].xmax); @@ -1244,8 +1231,8 @@ void FVTerm::updateVTerm (term_area* area) line_xmin++; // Don't update covered character } - _xmin = ax + line_xmin - ol; - _xmax = ax + line_xmax; + int _xmin = ax + line_xmin - ol; + int _xmax = ax + line_xmax; if ( _xmin < int(vterm->changes[ay + y].xmin) ) vterm->changes[ay + y].xmin = uInt(_xmin); @@ -1340,10 +1327,9 @@ void FVTerm::getArea (const FPoint& pos, term_area* area) if ( ! area ) return; - int y_end; - int length; int ax = pos.getX() - 1; int ay = pos.getY() - 1; + int y_end{}, length{}; if ( area->height + ay > vterm->height ) y_end = area->height - ay; @@ -1431,7 +1417,7 @@ void FVTerm::putArea (const FPoint& pos, term_area* area) int ay = pos.getY() - 1; int width = area->width + area->right_shadow; int height = area->height + area->bottom_shadow; - int ol = 0; // outside left + int ol{0}; // outside left int y_end{}, length{}; if ( ax < 0 ) @@ -2308,6 +2294,7 @@ void FVTerm::printRange ( uInt xmin, uInt xmax, uInt y auto& rp = TCAP(fc::t_repeat_char); auto print_char = &vt->text[y * uInt(vt->width) + x]; print_char->attr.bit.printed = true; + replaceNonPrintableFullwidth (x, print_char); // skip character with no changes if ( skipUnchangedCharacters(x, xmax, y) ) @@ -2326,14 +2313,193 @@ void FVTerm::printRange ( uInt xmin, uInt xmax, uInt y { repeatCharacter(x, xmax, y); } - else + else // General character output { - // General character output - appendCharacter (print_char); + bool min_and_not_max( x == xmin && xmin != xmax ); + printCharacter (x, y, min_and_not_max, print_char); + } + } +} + +//---------------------------------------------------------------------- +inline void FVTerm::replaceNonPrintableFullwidth ( uInt x + , charData*& print_char ) +{ + // Replace non-printable full-width characters that are truncated + // from the right or left terminal side + + if ( x == 0 && isFullWidthPaddingChar(print_char) ) + { + print_char->code = fc::SingleLeftAngleQuotationMark; // ‹ + print_char->attr.bit.fullwidth_padding = false; + } + else if ( x == uInt(vterm->width - 1) + && isFullWidthChar(print_char) ) + { + print_char->code = fc::SingleRightAngleQuotationMark; // › + print_char->attr.bit.char_width = 1; + } +} + +//---------------------------------------------------------------------- +void FVTerm::printCharacter ( uInt& x, uInt y, bool min_and_not_max + , charData*& print_char) +{ + // General character output on terminal + + if ( x < uInt(vterm->width - 1) && isFullWidthChar(print_char) ) + { + printFullWidthCharacter (x, y, print_char); + } + else if ( x > 0 && x < uInt(vterm->width - 1) + && isFullWidthPaddingChar(print_char) ) + { + printFullWidthPaddingCharacter (x, y, print_char); + } + else if ( x > 0 && min_and_not_max ) + { + printHalfCovertFullWidthCharacter (x, y, print_char); + } + else + { + // Print a half-width character + appendCharacter (print_char); + markAsPrinted (x, y); + } +} + +//---------------------------------------------------------------------- +void FVTerm::printFullWidthCharacter ( uInt& x, uInt y + , charData*& print_char ) +{ + auto vt = vterm; + auto next_char = &vt->text[y * uInt(vt->width) + x + 1]; + + if ( print_char->attr.byte[0] == next_char->attr.byte[0] + && print_char->attr.byte[1] == next_char->attr.byte[1] + && print_char->fg_color == next_char->fg_color + && print_char->bg_color == next_char->bg_color + && isFullWidthChar(print_char) + && isFullWidthPaddingChar(next_char) ) + { + // Print a full-width character + appendCharacter (print_char); + markAsPrinted (x, y); + skipPaddingCharacter (x, y, print_char); + } + else + { + // Print ellipses for the 1st full-width character column + appendAttributes (print_char); + appendOutputBuffer (fc::HorizontalEllipsis); + term_pos->x_ref()++; + markAsPrinted (x, y); + + if ( isFullWidthPaddingChar(next_char) ) + { + // Print ellipses for the 2nd full-width character column + x++; + appendAttributes (next_char); + appendOutputBuffer (fc::HorizontalEllipsis); + term_pos->x_ref()++; markAsPrinted (x, y); } } } + +//---------------------------------------------------------------------- +void FVTerm::printFullWidthPaddingCharacter ( uInt& x, uInt y + , charData*& print_char) +{ + auto vt = vterm; + auto prev_char = &vt->text[y * uInt(vt->width) + x - 1]; + + if ( print_char->attr.byte[0] == prev_char->attr.byte[0] + && print_char->attr.byte[1] == prev_char->attr.byte[1] + && print_char->fg_color == prev_char->fg_color + && print_char->bg_color == prev_char->bg_color + && isFullWidthChar(prev_char) + && isFullWidthPaddingChar(print_char) ) + { + // Move cursor one character to the left + auto& le = TCAP(fc::t_cursor_left); + auto& RI = TCAP(fc::t_parm_right_cursor); + + if ( le ) + appendOutputBuffer (le); + else if ( RI ) + appendOutputBuffer (tparm(RI, 1, 0, 0, 0, 0, 0, 0, 0, 0)); + else + { + skipPaddingCharacter (x, y, prev_char); + return; + } + + // Print a full-width character + x--; + term_pos->x_ref()--; + appendCharacter (prev_char); + markAsPrinted (x, y); + skipPaddingCharacter (x, y, prev_char); + } + else + { + // Print ellipses for the 1st full-width character column + appendAttributes (print_char); + appendOutputBuffer (fc::HorizontalEllipsis); + term_pos->x_ref()++; + markAsPrinted (x, y); + } +} + +//---------------------------------------------------------------------- +void FVTerm::printHalfCovertFullWidthCharacter ( uInt& x, uInt y + , charData*& print_char ) +{ + auto vt = vterm; + auto prev_char = &vt->text[y * uInt(vt->width) + x - 1]; + + if ( isFullWidthChar(prev_char) && ! isFullWidthPaddingChar(print_char) ) + { + // Move cursor one character to the left + auto& le = TCAP(fc::t_cursor_left); + auto& RI = TCAP(fc::t_parm_right_cursor); + + if ( le ) + appendOutputBuffer (le); + else if ( RI ) + appendOutputBuffer (tparm(RI, 1, 0, 0, 0, 0, 0, 0, 0, 0)); + + if ( le || RI ) + { + // Print ellipses for the 1st full-width character column + x--; + term_pos->x_ref()--; + appendAttributes (print_char); + appendOutputBuffer (fc::HorizontalEllipsis); + term_pos->x_ref()++; + markAsPrinted (x, y); + x++; + } + } + + // Print a half-width character + appendCharacter (print_char); + markAsPrinted (x, y); +} + +//---------------------------------------------------------------------- +inline void FVTerm::skipPaddingCharacter ( uInt& x, uInt y + , charData*& print_char ) +{ + if ( isFullWidthChar(print_char) ) // full-width character + { + x++; // Skip the following padding character + term_pos->x_ref()++; + markAsPrinted (x, y); + } +} + //---------------------------------------------------------------------- FVTerm::exit_state FVTerm::eraseCharacters ( uInt& x, uInt xmax, uInt y , bool draw_trailing_ws ) @@ -2347,7 +2513,7 @@ FVTerm::exit_state FVTerm::eraseCharacters ( uInt& x, uInt xmax, uInt y if ( ! ec || print_char->code != ' ' ) return not_used; - uInt whitespace = 1; + uInt whitespace{1}; bool normal = FTerm::isNormal(print_char); for (uInt i = x + 1; i <= xmax; i++) @@ -2358,6 +2524,7 @@ FVTerm::exit_state FVTerm::eraseCharacters ( uInt& x, uInt xmax, uInt y whitespace++; else break; + } if ( whitespace == 1 ) @@ -2454,6 +2621,18 @@ FVTerm::exit_state FVTerm::repeatCharacter (uInt& x, uInt xmax, uInt y) return used; } +//---------------------------------------------------------------------- +inline bool FVTerm::isFullWidthChar (charData*& ch) +{ + return bool(ch->attr.bit.char_width == 2); +} + +//---------------------------------------------------------------------- +inline bool FVTerm::isFullWidthPaddingChar (charData*& ch) +{ + return ch->attr.bit.fullwidth_padding; +} + //---------------------------------------------------------------------- void FVTerm::cursorWrap() { @@ -2507,6 +2686,34 @@ bool FVTerm::printWrap (term_area* area) return end_of_area; } +//---------------------------------------------------------------------- +void FVTerm::printPaddingCharacter (term_area* area, charData& term_char) +{ + // Creates a padding-character from the current character (term_char) + // and prints it. It is a placeholder for the column after + // a full-width character. + + charData pc; // padding character + + // Copy character to padding character + std::memcpy (&pc, &term_char, sizeof(pc)); + + if ( getEncoding() == fc::UTF8 ) + { + pc.code = 0; + pc.attr.bit.fullwidth_padding = true; + pc.attr.bit.char_width = 0; + } + else + { + pc.code = '.'; + pc.attr.bit.char_width = 1; + } + + // Print the padding-character + print (area, pc); +} + //---------------------------------------------------------------------- void FVTerm::updateTerminalLine (uInt y) { diff --git a/src/fwidget.cpp b/src/fwidget.cpp index 87bd2278..b03da4e1 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -1250,10 +1250,10 @@ void FWidget::drawShadow() return; } - int x1 = 1 - , x2 = int(getWidth()) - , y1 = 1 - , y2 = int(getHeight()); + int x1 = 1; + int x2 = int(getWidth()); + int y1 = 1; + int y2 = int(getHeight()); if ( flags.trans_shadow ) { @@ -1310,10 +1310,10 @@ void FWidget::drawFlatBorder() if ( ! isNewFont() ) return; - int x1 = 1 - , x2 = int(getWidth()) + 1 - , y1 = 0 - , y2 = int(getHeight()) + 1; + int x1 = 1; + int x2 = int(getWidth() + 1); + int y1 = 0; + int y2 = int(getHeight() + 1); if ( auto p = getParentWidget() ) setColor (wcolors.dialog_fg, p->getBackgroundColor()); @@ -1377,10 +1377,10 @@ void FWidget::clearFlatBorder() if ( ! isNewFont() ) return; - int x1 = 1 - , x2 = int(getWidth()) + 1 - , y1 = 0 - , y2 = int(getHeight()) + 1; + int x1 = 1; + int x2 = int(getWidth() + 1); + int y1 = 0; + int y2 = int(getHeight() + 1); if ( auto p = getParentWidget() ) setColor (wcolors.dialog_fg, p->getBackgroundColor()); @@ -1548,9 +1548,9 @@ void FWidget::adjustSize() else if ( ignore_padding && p ) { woffset.setCoordinates ( p->getTermX() - 1 - , p->getTermY() - 1 - , p->getTermX() + int(p->getWidth()) - 2 - , p->getTermY() + int(p->getHeight()) - 2 ); + , p->getTermY() - 1 + , p->getTermX() + int(p->getWidth()) - 2 + , p->getTermY() + int(p->getHeight()) - 2 ); } else if ( p ) woffset = p->wclient_offset; diff --git a/src/fwindow.cpp b/src/fwindow.cpp index 953751d3..4dfcd3d7 100644 --- a/src/fwindow.cpp +++ b/src/fwindow.cpp @@ -782,18 +782,18 @@ void FWindow::setShadowSize (const FSize& size) //---------------------------------------------------------------------- void FWindow::adjustSize() { - int old_x = getX(); - int old_y = getY(); + int old_x = getTermX(); + int old_y = getTermY(); FWidget::adjustSize(); if ( zoomed ) setGeometry (FPoint(1, 1), FSize(getMaxWidth(), getMaxHeight()), false); else if ( isVirtualWindow() ) { - if ( getX() != old_x ) + if ( getTermX() != old_x ) getVWin()->offset_left = getTermX() - 1; - if ( getY() != old_y ) + if ( getTermY() != old_y ) getVWin()->offset_top = getTermY() - 1; } } diff --git a/src/include/final/fapplication.h b/src/include/final/fapplication.h index d3d66dd9..ba94156c 100644 --- a/src/include/final/fapplication.h +++ b/src/include/final/fapplication.h @@ -79,6 +79,7 @@ class FCloseEvent; class FFocusEvent; class FKeyEvent; class FMouseEvent; +class FStartOptions; class FTimerEvent; class FWheelEvent; class FMouseControl; @@ -144,6 +145,7 @@ class FApplication : public FWidget // Methods void init (uInt64, uInt64); static void cmd_options (const int&, char*[]); + static FStartOptions& getStartOptions(); void findKeyboardWidget(); bool isKeyPressed(); void keyPressed(); diff --git a/src/include/final/fbutton.h b/src/include/final/fbutton.h index 3490c7de..33ad6340 100644 --- a/src/include/final/fbutton.h +++ b/src/include/final/fbutton.h @@ -173,7 +173,7 @@ class FButton : public FWidget std::size_t indent{0}; std::size_t center_offset{0}; std::size_t vcenter_offset{0}; - std::size_t txtlength{0}; + std::size_t column_width{0}; }; // FButton inline functions diff --git a/src/include/final/fc.h b/src/include/final/fc.h index 1971e82c..e5beaf63 100644 --- a/src/include/final/fc.h +++ b/src/include/final/fc.h @@ -152,6 +152,9 @@ enum SpecialCharacter : wchar_t DownwardsArrow = 0x2193, // ↓ RightwardsArrow = 0x2192, // → LeftwardsArrow = 0x2190, // ← + SingleRightAngleQuotationMark = 0x203a, // › (1) + SingleLeftAngleQuotationMark = 0x2039, // ‹ (1) + HorizontalEllipsis = 0x2026, // … (1) DoubleExclamationMark = 0x203c, // ‼ SuperscriptLatinSmallLetterN = 0x207f, // ⁿ GreaterThanOrEqualTo = 0x2265, // ≥ diff --git a/src/include/final/fcharmap.h b/src/include/final/fcharmap.h index 12f13533..df54c767 100644 --- a/src/include/final/fcharmap.h +++ b/src/include/final/fcharmap.h @@ -45,6 +45,9 @@ extern const std::size_t lastKeyItem; extern wchar_t cp437_to_ucs[][2]; extern const std::size_t lastCP437Item; +extern wchar_t halfWidth_fullWidth[][2]; +extern const std::size_t lastHalfWidthItem; + } // namespace fc } // namespace finalcut diff --git a/src/include/final/flabel.h b/src/include/final/flabel.h index bcf75b63..473c7a34 100644 --- a/src/include/final/flabel.h +++ b/src/include/final/flabel.h @@ -105,11 +105,11 @@ class FLabel : public FWidget // Mutators void setAccelWidget (FWidget* = nullptr); - void setAlignment(fc::text_alignment); - bool setEmphasis(bool); + void setAlignment (fc::text_alignment); + bool setEmphasis (bool); bool setEmphasis(); bool unsetEmphasis(); - bool setReverseMode(bool); + bool setReverseMode (bool); bool setReverseMode(); bool unsetReverseMode(); bool setEnable (bool) override; @@ -146,7 +146,7 @@ class FLabel : public FWidget void draw() override; void drawMultiLine(); void drawSingleLine(); - void printLine ( wchar_t[], std::size_t + void printLine ( wchar_t[], std::size_t, std::size_t , std::size_t, std::size_t = 0 ); // Data members @@ -178,6 +178,10 @@ inline fc::text_alignment FLabel::getAlignment() inline FString& FLabel::getText() { return text; } +//---------------------------------------------------------------------- +inline bool FLabel::setEmphasis (bool enable) +{ return (emphasis = enable); } + //---------------------------------------------------------------------- inline bool FLabel::setEmphasis() { return setEmphasis(true); } @@ -186,6 +190,10 @@ inline bool FLabel::setEmphasis() inline bool FLabel::unsetEmphasis() { return setEmphasis(false); } +//---------------------------------------------------------------------- +inline bool FLabel::setReverseMode (bool enable) +{ return (reverse_mode = enable); } + //---------------------------------------------------------------------- inline bool FLabel::setReverseMode() { return setReverseMode(true); } diff --git a/src/include/final/flineedit.h b/src/include/final/flineedit.h index 4287d51e..438ba237 100644 --- a/src/include/final/flineedit.h +++ b/src/include/final/flineedit.h @@ -156,6 +156,9 @@ class FLineEdit : public FWidget void adjustSize() override; private: + // Typedef + typedef std::pair offsetPair; + // Enumeration enum dragScroll { @@ -164,19 +167,25 @@ class FLineEdit : public FWidget scrollRight = 2 }; + // Constants + static constexpr std::size_t NOT_SET = static_cast(-1); + // Methods void init(); bool hasHotkey(); void draw() override; void drawInputField(); - void keyLeft(); - void keyRight(); - void keyHome(); - void keyEnd(); - void keyDel(); - void keyBackspace(); - void keyInsert(); - void keyEnter(); + offsetPair endPosToOffset (std::size_t); + std::size_t clickPosToCursorPos (std::size_t); + void adjustTextOffset(); + void cursorLeft(); + void cursorRight(); + void cursorHome(); + void cursorEnd(); + void deleteCurrentCharacter(); + void deletePreviousCharacter(); + void switchInsertMode(); + void acceptInput(); bool keyInput (FKey); wchar_t characterFilter (const wchar_t); void processActivate(); @@ -192,8 +201,9 @@ class FLineEdit : public FWidget int scroll_repeat{100}; bool scroll_timer{false}; bool insert_mode{true}; - std::size_t cursor_pos{0}; + std::size_t cursor_pos{NOT_SET}; std::size_t text_offset{0}; + std::size_t char_width_offset{0}; std::size_t max_length{std::numeric_limits::max()}; }; diff --git a/src/include/final/flistbox.h b/src/include/final/flistbox.h index 42ac2ab4..52efa51c 100644 --- a/src/include/final/flistbox.h +++ b/src/include/final/flistbox.h @@ -290,19 +290,19 @@ class FListBox : public FWidget void scrollToY (int); void scrollLeft (int); void scrollRight (int); - void keyUp(); - void keyDown(); - void keyLeft(); - void keyRight(); - void keyPgUp(); - void keyPgDn(); - void keyHome(); - void keyEnd(); - bool keyEsc(); - void keyEnter(); - bool keySpace(); - bool keyInsert(); - bool keyBackspace(); + void scrollLeft(); + void scrollRight(); + void onePosUp(); + void onePosDown(); + void onePageUp(); + void onePageDown(); + void firstPos(); + void lastPos(); + bool skipIncrementalSearch(); + void acceptSelection(); + bool spacebarProcessing(); + bool changeSelectionAndPosition(); + bool deletePreviousCharacter(); bool keyIncSearchInput (FKey); void processClick(); void processSelect(); diff --git a/src/include/final/flistview.h b/src/include/final/flistview.h index 0c63f09d..3a7eabb4 100644 --- a/src/include/final/flistview.h +++ b/src/include/final/flistview.h @@ -394,6 +394,7 @@ class FListView : public FWidget void drawSortIndicator (std::size_t&, std::size_t); void drawHeadlineLabel (const headerItems::const_iterator&); void drawHeaderBorder (std::size_t); + void drawBufferedHeadline(); void drawColumnEllipsis ( const headerItems::const_iterator& , const FString& ); void updateDrawing (bool, bool); @@ -413,13 +414,13 @@ class FListView : public FWidget FObjectIterator appendItem (FListViewItem*); void processClick(); void processChanged(); - void keySpace(); - void keyLeft (int&); - void keyRight (int&); - void keyHome(); - void keyEnd(); - bool keyPlus(); - bool keyMinus(); + void toggleCheckbox(); + void collapseAndScrollLeft (int&); + void expandAndScrollRight (int&); + void firstPos(); + void lastPos(); + bool expandSubtree(); + bool collapseSubtree(); void setRelativePosition (int); void stepForward(); void stepBackward(); diff --git a/src/include/final/fmenu.h b/src/include/final/fmenu.h index bf1c9b06..13666787 100644 --- a/src/include/final/fmenu.h +++ b/src/include/final/fmenu.h @@ -210,12 +210,10 @@ class FMenu : public FWindow, public FMenuList void drawTrailingSpaces (std::size_t); void setLineAttributes (FMenuItem*, int); void setCursorToHotkeyPosition (FMenuItem*); - void keyUp(); - void keyDown(); - void keyLeft (FKeyEvent*); - void keyRight (FKeyEvent*); - void keyEnter(); - void keyEscape(); + void selectPrevMenu (FKeyEvent*); + void selectNextMenu (FKeyEvent*); + void acceptSelection(); + void closeMenu(); void processActivate(); // Friend classes @@ -227,7 +225,7 @@ class FMenu : public FWindow, public FMenuList friend class FRadioMenuItem; // Data members - FMenuItem item{}; + FMenuItem menuitem{}; FWidget* super_menu{nullptr}; FMenu* opened_sub_menu{nullptr}; FMenu* shown_sub_menu{nullptr}; @@ -245,35 +243,35 @@ inline const char* FMenu::getClassName() const //---------------------------------------------------------------------- inline FString FMenu::getText() const -{ return item.getText(); } +{ return menuitem.getText(); } //---------------------------------------------------------------------- inline FMenuItem* FMenu::getItem() -{ return &item; } +{ return &menuitem; } //---------------------------------------------------------------------- inline bool FMenu::setEnable (bool enable) -{ return item.setEnable(enable); } +{ return menuitem.setEnable(enable); } //---------------------------------------------------------------------- inline bool FMenu::setEnable() -{ return item.setEnable(); } +{ return menuitem.setEnable(); } //---------------------------------------------------------------------- inline bool FMenu::unsetEnable() -{ return item.unsetEnable(); } +{ return menuitem.unsetEnable(); } //---------------------------------------------------------------------- inline bool FMenu::setDisable() -{ return item.setDisable(); } +{ return menuitem.setDisable(); } //---------------------------------------------------------------------- inline void FMenu::setSelected() -{ item.setSelected(); } +{ menuitem.setSelected(); } //---------------------------------------------------------------------- inline void FMenu::unsetSelected() -{ item.unsetSelected(); } +{ menuitem.unsetSelected(); } //---------------------------------------------------------------------- inline bool FMenu::setMenuWidget() @@ -285,27 +283,27 @@ inline bool FMenu::unsetMenuWidget() //---------------------------------------------------------------------- inline void FMenu::setMenu (FMenu* m) -{ item.setMenu(m); } +{ menuitem.setMenu(m); } //---------------------------------------------------------------------- inline void FMenu::setText (const FString& txt) -{ item.setText(txt); } +{ menuitem.setText(txt); } //---------------------------------------------------------------------- inline bool FMenu::isEnabled() const -{ return item.isEnabled(); } +{ return menuitem.isEnabled(); } //---------------------------------------------------------------------- inline bool FMenu::isSelected() const -{ return item.isSelected(); } +{ return menuitem.isSelected(); } //---------------------------------------------------------------------- inline bool FMenu::hasHotkey() const -{ return item.hasHotkey(); } +{ return menuitem.hasHotkey(); } //---------------------------------------------------------------------- inline bool FMenu::hasMenu() const -{ return item.hasMenu(); } +{ return menuitem.hasMenu(); } //---------------------------------------------------------------------- inline FWidget* FMenu::getSuperMenu() const @@ -325,7 +323,7 @@ inline FMenu* FMenu::superMenuAt (const FPoint& p) //---------------------------------------------------------------------- inline void FMenu::onAccel (FAccelEvent* ev) -{ item.onAccel(ev); } +{ menuitem.onAccel(ev); } } // namespace finalcut diff --git a/src/include/final/fmenubar.h b/src/include/final/fmenubar.h index d93017db..6578f82a 100644 --- a/src/include/final/fmenubar.h +++ b/src/include/final/fmenubar.h @@ -132,6 +132,7 @@ class FMenuBar : public FWindow, public FMenuList void drawItems(); void drawItem (FMenuItem*, std::size_t&); void setLineAttributes (FMenuItem*); + void setCursorToHotkeyPosition (FMenuItem*, std::size_t); void drawMenuText (menuText&); void drawEllipsis (const menuText&, std::size_t); void drawLeadingSpace (std::size_t&); diff --git a/src/include/final/fmenuitem.h b/src/include/final/fmenuitem.h index 3ada23bd..d4be35a1 100644 --- a/src/include/final/fmenuitem.h +++ b/src/include/final/fmenuitem.h @@ -94,9 +94,10 @@ class FMenuItem : public FWidget // Accessors const char* getClassName() const override; - uChar getHotkey() const; + FKey getHotkey() const; FMenu* getMenu() const; std::size_t getTextLength() const; + std::size_t getTextWidth() const; FString getText() const; // Mutators @@ -159,7 +160,6 @@ class FMenuItem : public FWidget // Methods void init (FWidget*); - uChar hotKey(); void updateSuperMenuDimensions(); void processActivate(); void processDeactivate(); @@ -179,8 +179,9 @@ class FMenuItem : public FWidget FWidget* super_menu{nullptr}; FDialog* associated_window{nullptr}; std::size_t text_length{0}; + std::size_t text_width{0}; FKey accel_key{0}; - uChar hotkey{0}; + FKey hotkey{0}; bool selected{false}; bool separator{false}; bool checkable{false}; @@ -202,7 +203,7 @@ inline const char* FMenuItem::getClassName() const { return "FMenuItem"; } //---------------------------------------------------------------------- -inline uChar FMenuItem::getHotkey() const +inline FKey FMenuItem::getHotkey() const { return hotkey; } //---------------------------------------------------------------------- @@ -213,6 +214,10 @@ inline FMenu* FMenuItem::getMenu() const inline std::size_t FMenuItem::getTextLength() const { return text_length; } +//---------------------------------------------------------------------- +inline std::size_t FMenuItem::getTextWidth() const +{ return text_width; } + //---------------------------------------------------------------------- inline FString FMenuItem::getText() const { return text; } diff --git a/src/include/final/fmessagebox.h b/src/include/final/fmessagebox.h index 6665832c..fb3748b9 100644 --- a/src/include/final/fmessagebox.h +++ b/src/include/final/fmessagebox.h @@ -155,14 +155,13 @@ class FMessageBox : public FDialog // Data members FString headline_text{}; FString text{}; - FString* text_components{nullptr}; - FStringList text_split{}; + FStringList text_components{}; FButton* button[3]{nullptr}; std::size_t max_line_width{0}; FColor emphasis_color{getFWidgetColors().dialog_emphasis_fg}; int button_digit[3]{0}; uInt num_buttons{0}; - uInt text_num_lines{0}; + std::size_t text_num_lines{0}; bool center_text{false}; }; diff --git a/src/include/final/foptiattr.h b/src/include/final/foptiattr.h index c016c9d6..7568e85a 100644 --- a/src/include/final/foptiattr.h +++ b/src/include/final/foptiattr.h @@ -342,7 +342,9 @@ inline bool operator == ( const charData& lhs, && lhs.fg_color == rhs.fg_color && lhs.bg_color == rhs.bg_color && lhs.attr.byte[0] == rhs.attr.byte[0] - && lhs.attr.byte[1] == rhs.attr.byte[1]; + && lhs.attr.byte[1] == rhs.attr.byte[1] + && lhs.attr.bit.fullwidth_padding \ + == rhs.attr.bit.fullwidth_padding; } //---------------------------------------------------------------------- diff --git a/src/include/final/fstartoptions.h b/src/include/final/fstartoptions.h index 2961fc6e..ca94deee 100644 --- a/src/include/final/fstartoptions.h +++ b/src/include/final/fstartoptions.h @@ -35,6 +35,11 @@ #error "Only can be included directly." #endif +#include + +#include "final/fc.h" +#include "final/ftypes.h" + namespace finalcut { @@ -42,27 +47,26 @@ namespace finalcut // class FStartOptions //---------------------------------------------------------------------- -struct FStartOptions +class FStartOptions final { public: - // Mutator - void setDefault() - { - cursor_optimisation = true; - mouse_support = true; - terminal_detection = true; - color_change = true; - vgafont = false; - newfont = false; - encoding = fc::UNKNOWN; + // Constructors + FStartOptions(); -#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST) - meta_sends_escape = true; - change_cursorstyle = true; -#elif defined(__NetBSD__) || defined(__OpenBSD__) - meta_sends_escape = true; -#endif - } + // Disable copy constructor + FStartOptions (const FStartOptions&) = delete; + + // Destructor + virtual ~FStartOptions(); + + // Disable assignment operator (=) + FStartOptions& operator = (const FStartOptions&) = delete; + + // Accessors + static FStartOptions& getFStartOptions(); + + // Mutator + void setDefault(); // Data members uInt8 cursor_optimisation : 1; @@ -75,20 +79,17 @@ struct FStartOptions fc::encoding encoding; #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST) - uInt8 meta_sends_escape : 1; - uInt8 change_cursorstyle : 1; - uInt8 : 6; // padding bits + uInt8 meta_sends_escape : 1; + uInt8 change_cursorstyle : 1; + uInt8 : 6; // padding bits #elif defined(__NetBSD__) || defined(__OpenBSD__) - uInt8 meta_sends_escape : 1; - uInt8 : 7; // padding bits + uInt8 meta_sends_escape : 1; + uInt8 : 7; // padding bits #endif + + static FStartOptions* start_options; }; -static struct FStartOptions start_options{}; - -inline FStartOptions& getStartOptions() -{ return start_options; } - } // namespace finalcut #endif // FSTARTOPTIONS_H diff --git a/src/include/final/fstatusbar.h b/src/include/final/fstatusbar.h index 6e6fde57..68359c9a 100644 --- a/src/include/final/fstatusbar.h +++ b/src/include/final/fstatusbar.h @@ -238,6 +238,8 @@ class FStatusBar : public FWindow // Methods void init(); + int getKeyNameWidth (const FStatusKey*); + int getKeyTextWidth (const FStatusKey*); void draw() override; void drawKeys(); void drawKey (keyList::const_iterator); diff --git a/src/include/final/fstring.h b/src/include/final/fstring.h index f9fdc047..a08c934d 100644 --- a/src/include/final/fstring.h +++ b/src/include/final/fstring.h @@ -78,7 +78,8 @@ class FString { public: // Typedef - typedef const wchar_t* iterator; + typedef const wchar_t* const_iterator; + typedef wchar_t* iterator; // Constructors FString () = default; @@ -191,12 +192,15 @@ class FString std::size_t getUTF8length() const; std::size_t capacity() const; - iterator begin() const; - iterator end() const; + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; wchar_t front() const; - wchar_t back() const; + wchar_t back() const; - FString& sprintf (const FString, ...); + template + FString& sprintf (const FString, Args&&...); FString clear(); const wchar_t* wc_str() const; @@ -369,11 +373,19 @@ inline std::size_t FString::capacity() const { return ( length > 0 ) ? bufsize - 1 : 0; } //---------------------------------------------------------------------- -inline FString::iterator FString::begin() const +inline FString::iterator FString::begin() { return string; } //---------------------------------------------------------------------- -inline FString::iterator FString::end() const +inline FString::iterator FString::end() +{ return string + length; } + +//---------------------------------------------------------------------- +inline FString::const_iterator FString::begin() const +{ return string; } + +//---------------------------------------------------------------------- +inline FString::const_iterator FString::end() const { return string + length; } //---------------------------------------------------------------------- @@ -390,6 +402,25 @@ inline wchar_t FString::back() const return string[length - 1]; } +//---------------------------------------------------------------------- +template +inline FString& FString::sprintf (const FString format, Args&&... args) +{ + static constexpr int BUFSIZE = 4096; + wchar_t buffer[BUFSIZE]{}; + + if ( ! format ) + { + clear(); + return *this; + } + + std::swprintf ( buffer, BUFSIZE + , format.wc_str(), std::forward(args)... ); + _assign(buffer); + return *this; +} + //---------------------------------------------------------------------- template inline FString& FString::setNumber (NumT num, int precision) diff --git a/src/include/final/fterm.h b/src/include/final/fterm.h index c2910556..14d07785 100644 --- a/src/include/final/fterm.h +++ b/src/include/final/fterm.h @@ -116,6 +116,7 @@ #include "final/fc.h" #include "final/fstring.h" +#include "final/fsystem.h" namespace finalcut { @@ -125,9 +126,10 @@ class FKeyboard; class FMouseControl; class FOptiAttr; class FOptiMove; +class FStartOptions; class FSize; class FString; -class FSystem; +class FTermBuffer; class FTermData; class FTermDebugData; class FTermDetection; @@ -272,8 +274,6 @@ class FTerm final static bool charEncodable (wchar_t); static wchar_t charEncode (wchar_t); static wchar_t charEncode (wchar_t, fc::encoding); - static wchar_t cp437_to_unicode (uChar); - static uChar unicode_to_cp437 (wchar_t); static bool scrollTermForward(); static bool scrollTermReverse(); @@ -281,13 +281,8 @@ class FTerm final // function pointer -> static function static int (*Fputchar)(int); - static void putstringf (const char[], ...) -#if defined(__clang__) - __attribute__ ((__format__ (__printf__, 1, 2))) -#elif defined(__GNUC__) - __attribute__ ((format (printf, 1, 2))) -#endif - ; + template + static void putstringf (const char[], Args&&...); static void putstring (const char[], int = 1); static int putchar_ASCII (int); static int putchar_UTF8 (int); @@ -303,6 +298,7 @@ class FTerm final ; private: // Methods + static FStartOptions& getStartOptions(); static void init_global_values (bool); static void init_terminal_device_path(); static void oscPrefix(); @@ -386,6 +382,21 @@ class FTerm final }; +// non-member function forward declarations +//---------------------------------------------------------------------- +wchar_t cp437_to_unicode (uChar); +uChar unicode_to_cp437 (wchar_t); +FString getFullWidth (const FString&); +FString getHalfWidth (const FString&); +std::size_t getColumnWidthToLength (const FString&, std::size_t); +FString getColumnSubString (const FString&, std::size_t, std::size_t); +std::size_t getColumnWidth (const FString&, std::size_t); +std::size_t getColumnWidth (const FString&); +std::size_t getColumnWidth (const wchar_t); +std::size_t getColumnWidth (charData&); +std::size_t getColumnWidth (const FTermBuffer&); + + // FTerm inline functions //---------------------------------------------------------------------- inline const char* FTerm::getClassName() const @@ -403,6 +414,16 @@ inline bool FTerm::setUTF8() inline bool FTerm::unsetUTF8() { return setUTF8(false); } +//---------------------------------------------------------------------- +template +inline void FTerm::putstringf (const char format[], Args&&... args) +{ + char buf[512]{}; + char* str = buf; + std::snprintf (str, sizeof(buf), format, std::forward(args)...); + fsys->tputs (str, 1, FTerm::putchar_ASCII); +} + } // namespace finalcut diff --git a/src/include/final/ftermbuffer.h b/src/include/final/ftermbuffer.h index cd36625e..c1c3da75 100644 --- a/src/include/final/ftermbuffer.h +++ b/src/include/final/ftermbuffer.h @@ -53,10 +53,14 @@ class FTermBuffer { public: // Typedef - typedef std::vector charDataVector; + typedef std::vector charDataVector; + typedef charDataVector::iterator iterator; + typedef charDataVector::const_iterator const_iterator; // Constructor FTermBuffer() = default; + template + FTermBuffer (Iterator, Iterator); // Destructor virtual ~FTermBuffer(); @@ -64,6 +68,7 @@ class FTermBuffer // Overloaded operators template FTermBuffer& operator << (const typeT&); + FTermBuffer& operator << (const charDataVector&); FTermBuffer& operator << (const std::string&); FTermBuffer& operator << (const std::wstring&); FTermBuffer& operator << (const FColorPair&); @@ -81,8 +86,16 @@ class FTermBuffer bool isEmpty() const; // Methods + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + charData front() const; + charData back() const; + const FString toString() const; void clear(); - int writef (const FString, ...); + template + int writef (const FString, Args&&...); int write (const FString&); int write (wchar_t); void write (const FColorPair&); @@ -94,6 +107,13 @@ class FTermBuffer // FTermBuffer inline functions +//---------------------------------------------------------------------- +template +inline FTermBuffer::FTermBuffer(Iterator first, Iterator last) +{ + data.assign(first, last); +} + //---------------------------------------------------------------------- template inline FTermBuffer& FTermBuffer::operator << (const typeT& s) @@ -107,6 +127,15 @@ inline FTermBuffer& FTermBuffer::operator << (const typeT& s) return *this; } +//---------------------------------------------------------------------- +inline FTermBuffer& FTermBuffer::operator << (const charDataVector& vec) +{ + for (auto&& tc : vec) + data.push_back(tc); + + return *this; +} + //---------------------------------------------------------------------- inline FTermBuffer& FTermBuffer::operator << (const std::string& string) { @@ -144,6 +173,30 @@ inline const FTermBuffer::charDataVector& FTermBuffer::getBuffer() const inline bool FTermBuffer::isEmpty() const { return data.empty(); } +//---------------------------------------------------------------------- +inline FTermBuffer::iterator FTermBuffer::begin() +{ return data.begin(); } + +//---------------------------------------------------------------------- +inline FTermBuffer::iterator FTermBuffer::end() +{ return data.end(); } + +//---------------------------------------------------------------------- +inline FTermBuffer::const_iterator FTermBuffer::begin() const +{ return data.begin(); } + +//---------------------------------------------------------------------- +inline FTermBuffer::const_iterator FTermBuffer::end() const +{ return data.end(); } + +//---------------------------------------------------------------------- +inline charData FTermBuffer::front() const +{ return data.front(); } + +//---------------------------------------------------------------------- +inline charData FTermBuffer::back() const +{ return data.back(); } + //---------------------------------------------------------------------- inline void FTermBuffer::clear() { @@ -151,6 +204,22 @@ inline void FTermBuffer::clear() data.shrink_to_fit(); } +//---------------------------------------------------------------------- +template +inline int FTermBuffer::writef (const FString format, Args&&... args) +{ + static constexpr int BUFSIZE = 4096; + wchar_t buffer[BUFSIZE]{}; + + if ( format.isEmpty() ) + return 0; + + std::swprintf ( buffer, BUFSIZE + , format.wc_str(), std::forward(args)... ); + FString str(buffer); + return write(str); +} + //---------------------------------------------------------------------- inline FTermBuffer& FTermBuffer::write() { return *this; } diff --git a/src/include/final/ftextview.h b/src/include/final/ftextview.h index afd8a328..3e571106 100644 --- a/src/include/final/ftextview.h +++ b/src/include/final/ftextview.h @@ -148,6 +148,7 @@ class FTextView : public FWidget , FTextViewCallback ); void draw() override; void drawText(); + bool isPrintable (wchar_t); void processChanged(); // Callback methods diff --git a/src/include/final/ftooltip.h b/src/include/final/ftooltip.h index 624f98ce..5eb4f3bf 100644 --- a/src/include/final/ftooltip.h +++ b/src/include/final/ftooltip.h @@ -107,8 +107,7 @@ class FToolTip : public FWindow // Data members FString text{}; - FString* text_components{nullptr}; - FStringList text_split{}; + FStringList text_components{}; std::size_t max_line_width{0}; std::size_t text_num_lines{0}; }; diff --git a/src/include/final/ftypes.h b/src/include/final/ftypes.h index 69cc2f75..8954ea67 100644 --- a/src/include/final/ftypes.h +++ b/src/include/final/ftypes.h @@ -118,30 +118,31 @@ typedef struct struct { // Attribute byte #0 - uInt8 bold : 1; // bold - uInt8 dim : 1; // dim - uInt8 italic : 1; // italic - uInt8 underline : 1; // underline - uInt8 blink : 1; // blink - uInt8 reverse : 1; // reverse - uInt8 standout : 1; // standout - uInt8 invisible : 1; // invisible + uInt8 bold : 1; // bold + uInt8 dim : 1; // dim + uInt8 italic : 1; // italic + uInt8 underline : 1; // underline + uInt8 blink : 1; // blink + uInt8 reverse : 1; // reverse + uInt8 standout : 1; // standout + uInt8 invisible : 1; // invisible // Attribute byte #1 - uInt8 protect : 1; // protect mode - uInt8 crossed_out : 1; // crossed out - uInt8 dbl_underline : 1; // double underline - uInt8 alt_charset : 1; // alternate character set (vt100) - uInt8 pc_charset : 1; // pc character set (CP437) - uInt8 transparent : 1; // transparent - uInt8 trans_shadow : 1; // transparent shadow - uInt8 inherit_bg : 1; // inherit background + uInt8 protect : 1; // protect mode + uInt8 crossed_out : 1; // crossed out + uInt8 dbl_underline : 1; // double underline + uInt8 alt_charset : 1; // alternate character set (vt100) + uInt8 pc_charset : 1; // pc character set (CP437) + uInt8 transparent : 1; // transparent + uInt8 trans_shadow : 1; // transparent shadow + uInt8 inherit_bg : 1; // inherit background // Attribute byte #2 - uInt8 no_changes : 1; // no changes required - uInt8 printed : 1; // is printed to VTerm - uInt8 char_with : 2; // Number of character cells on screen - uInt8 : 4; // padding bits + uInt8 no_changes : 1; // no changes required + uInt8 printed : 1; // is printed to VTerm + uInt8 fullwidth_padding : 1; // padding char (after a full-width char) + uInt8 char_width : 2; // number of character cells on screen + uInt8 : 3; // padding bits // Attribute byte #3 - uInt8 : 8; // padding byte + uInt8 : 8; // padding byte } bit; uInt8 byte[4]; diff --git a/src/include/final/fvterm.h b/src/include/final/fvterm.h index bfee073f..ca8b9039 100644 --- a/src/include/final/fvterm.h +++ b/src/include/final/fvterm.h @@ -291,7 +291,8 @@ class FVTerm , FPreprocessingHandler ); virtual void delPreprocessingHandler (FVTerm*); - int printf (const FString, ...); + template + int printf (const FString, Args&&...); int print (const FString&); int print (term_area*, const FString&); int print (const FTermBuffer&); @@ -440,10 +441,19 @@ class FVTerm static bool canClearTrailingWS (uInt&, uInt); bool skipUnchangedCharacters (uInt&, uInt, uInt); void printRange (uInt, uInt, uInt, bool); + void replaceNonPrintableFullwidth (uInt, charData*&); + void printCharacter (uInt&, uInt, bool, charData*&); + void printFullWidthCharacter (uInt&, uInt, charData*&); + void printFullWidthPaddingCharacter (uInt&, uInt, charData*&); + void printHalfCovertFullWidthCharacter (uInt&, uInt, charData*&); + void skipPaddingCharacter (uInt&, uInt, charData*&); exit_state eraseCharacters (uInt&, uInt, uInt, bool); exit_state repeatCharacter (uInt&, uInt, uInt); + bool isFullWidthChar (charData*&); + bool isFullWidthPaddingChar (charData*&); static void cursorWrap(); bool printWrap (term_area*); + void printPaddingCharacter (term_area*, charData&); void updateTerminalLine (uInt); bool updateTerminalCursor(); bool isInsideTerminal (const FPoint&); @@ -1033,6 +1043,22 @@ inline bool FVTerm::hasChangedTermSize() inline bool FVTerm::hasUTF8() { return FTerm::hasUTF8(); } +//---------------------------------------------------------------------- +template +inline int FVTerm::printf (const FString format, Args&&... args) +{ + static constexpr int BUFSIZE = 4096; + wchar_t buffer[BUFSIZE]{}; + + if ( format.isEmpty() ) + return 0; + + std::swprintf ( buffer, BUFSIZE + , format.wc_str(), std::forward(args)... ); + FString str(buffer); + return print(str); +} + //---------------------------------------------------------------------- inline FVTerm& FVTerm::print() { return *this; } diff --git a/test/Makefile.clang b/test/Makefile.clang index c2979c76..0f68b734 100644 --- a/test/Makefile.clang +++ b/test/Makefile.clang @@ -11,10 +11,12 @@ SRCS = $(wildcard *.cpp) OBJS = $(SRCS:%.cpp=%) CCXFLAGS = $(OPTIMIZE) $(PROFILE) $(DEBUG) -std=c++11 MAKEFILE = -f Makefile.clang -LDFLAGS = -L../src -lfinal -lcppunit -ldl +LDFLAGS = -L../src -lfinal $(TERMCAP) -lcppunit -ldl INCLUDES = -I. -I../src/include -I/usr/include/final RM = rm -f +TERMCAP := $(shell test -n "$$(ldd {/usr,}/lib64/libncursesw.so.5 2>/dev/null | grep libtinfo)" && echo "-ltinfo" || echo "-lncurses") + ifdef DEBUG OPTIMIZE = -O0 -fsanitize=undefined else @@ -28,11 +30,11 @@ endif all: $(OBJS) -debug: +unittest: $(MAKE) $(MAKEFILE) DEBUG="-g -D DEBUG -DUNIT_TEST -Wall -Wextra -Wpedantic -Wno-padded -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-implicit-fallthrough" check: test -test: debug +test: unittest $(OBJS) | sed -e "s/ OK/\x1b[32m OK\x1b[0m/g" -e "s/ failed/\x1b[31m failed\x1b[0m/g" profile: diff --git a/test/Makefile.gcc b/test/Makefile.gcc index 1f26b58a..7c598fa1 100644 --- a/test/Makefile.gcc +++ b/test/Makefile.gcc @@ -11,10 +11,12 @@ SRCS = $(wildcard *.cpp) OBJS = $(SRCS:%.cpp=%) CCXFLAGS = $(OPTIMIZE) $(PROFILE) $(DEBUG) -std=c++11 MAKEFILE = -f Makefile.gcc -LDFLAGS = -L../src -lfinal -lcppunit -ldl +LDFLAGS = -L../src -lfinal $(TERMCAP) -lcppunit -ldl INCLUDES = -I. -I../src/include -I/usr/include/final RM = rm -f +TERMCAP := $(shell test -n "$$(ldd {/usr,}/lib64/libncursesw.so.5 2>/dev/null | grep libtinfo)" && echo "-ltinfo" || echo "-lncurses") + ifdef DEBUG OPTIMIZE = -O0 else @@ -28,11 +30,11 @@ endif all: $(OBJS) -debug: +unittest: $(MAKE) $(MAKEFILE) DEBUG="-g -D DEBUG -DUNIT_TEST -Wall -Wextra -Wpedantic" check: test -test: debug +test: unittest $(OBJS) | sed -e "s/ OK/\x1b[32m OK\x1b[0m/g" -e "s/ failed/\x1b[31m failed\x1b[0m/g" profile: diff --git a/test/conemu.h b/test/conemu.h index 02171b2b..03e0e4ea 100644 --- a/test/conemu.h +++ b/test/conemu.h @@ -551,7 +551,8 @@ inline pid_t ConEmu::forkConEmu() while ( ! *shared_state && i < timeout ) { // Wait 10 ms (= 10,000,000 ns) - nanosleep ((const struct timespec[]){{0, 10000000L}}, NULL); + const struct timespec ms[]{{0, 10000000L}}; + nanosleep (ms, NULL); i++; } diff --git a/test/fkeyboard-test.cpp b/test/fkeyboard-test.cpp index 1715e2d5..f261ffa5 100644 --- a/test/fkeyboard-test.cpp +++ b/test/fkeyboard-test.cpp @@ -348,7 +348,8 @@ void FKeyboardTest::escapeKeyTest() input("\033"); processInput(); // Wait 100 ms (= 100,000,000 ns) - nanosleep ((const struct timespec[]){{0, 100000000L}}, NULL); + const struct timespec ms[]{{0, 100000000L}}; + nanosleep (ms, NULL); keyboard->escapeKeyHandling(); std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl; CPPUNIT_ASSERT ( key_pressed == finalcut::fc::Fkey_escape ); @@ -2078,7 +2079,8 @@ void FKeyboardTest::metaKeyTest() input("\033O"); processInput(); // Wait 100 ms - Substring keys needs a timeout - nanosleep ((const struct timespec[]){{0, 100000000L}}, NULL); + const struct timespec ms[]{{0, 100000000L}}; + nanosleep (ms, NULL); keyboard->escapeKeyHandling(); std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl; CPPUNIT_ASSERT ( key_pressed == finalcut::fc::Fmkey_O ); @@ -2165,7 +2167,7 @@ void FKeyboardTest::metaKeyTest() input("\033["); processInput(); // Wait 100 ms - Substring keys needs a timeout - nanosleep ((const struct timespec[]){{0, 100000000L}}, NULL); + nanosleep (ms, NULL); keyboard->escapeKeyHandling(); std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl; CPPUNIT_ASSERT ( key_pressed == finalcut::fc::Fmkey_left_square_bracket ); @@ -2182,7 +2184,7 @@ void FKeyboardTest::metaKeyTest() input("\033]"); processInput(); // Wait 100 ms - Substring keys needs a timeout - nanosleep ((const struct timespec[]){{0, 100000000L}}, NULL); + nanosleep (ms, NULL); keyboard->escapeKeyHandling(); std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl; CPPUNIT_ASSERT ( key_pressed == finalcut::fc::Fmkey_right_square_bracket ); diff --git a/test/fobject-test.cpp b/test/fobject-test.cpp index cb46d987..521dba2c 100644 --- a/test/fobject-test.cpp +++ b/test/fobject-test.cpp @@ -551,7 +551,8 @@ void FObjectTest::performTimerActionTest() { num_events += t1.processEvent(); // Wait 100 ms - nanosleep ((const struct timespec[]){{0, 100000000L}}, NULL); + const struct timespec ms[]{{0, 100000000L}}; + nanosleep (ms, NULL); loop++; } diff --git a/test/fstring-test.cpp b/test/fstring-test.cpp index 99a789ef..57f61f86 100644 --- a/test/fstring-test.cpp +++ b/test/fstring-test.cpp @@ -973,7 +973,7 @@ void FStringTest::iteratorTest() CPPUNIT_ASSERT ( str.front() == L'1' ); CPPUNIT_ASSERT ( str.back() == L'9' ); - finalcut::FString::iterator iter = str.begin(); + finalcut::FString::const_iterator iter = str.begin(); CPPUNIT_ASSERT ( (*iter) == L'1' ); ++iter; CPPUNIT_ASSERT ( (*iter) == L'2' ); @@ -993,6 +993,17 @@ void FStringTest::iteratorTest() CPPUNIT_ASSERT ( (*iter) == L'9' ); ++iter; CPPUNIT_ASSERT ( iter == str.end() ); + + finalcut::FString str2("bcdefg"); + finalcut::FString::iterator iter2 = str2.begin(); + + while ( iter2 != str2.end() ) + { + *iter2 -= 1; + ++iter2; + } + + CPPUNIT_ASSERT ( str2 == L"abcdef" ); } //---------------------------------------------------------------------- diff --git a/test/ftermfreebsd-test.cpp b/test/ftermfreebsd-test.cpp index 7360da54..fa0b4bcd 100644 --- a/test/ftermfreebsd-test.cpp +++ b/test/ftermfreebsd-test.cpp @@ -73,8 +73,8 @@ class FSystemTest : public finalcut::FSystem private: // Data members - std::string characters; - int cursor_type = 0; + std::string characters{}; + int cursor_type{0}; static keymap_t keymap; static keymap_t terminal_keymap; }; @@ -401,10 +401,10 @@ int FSystemTest::isTTY (int fd) //---------------------------------------------------------------------- int FSystemTest::ioctl (int fd, uLong request, ...) { - va_list args; - void* argp; - std::string req_string; - int ret_val = -1; + va_list args{}; + void* argp{}; + std::string req_string{}; + int ret_val{-1}; va_start (args, request); argp = va_arg (args, void*); @@ -481,7 +481,7 @@ int FSystemTest::ioctl (int fd, uLong request, ...) //---------------------------------------------------------------------- int FSystemTest::open (const char* pathname, int flags, ...) { - va_list args; + va_list args{}; va_start (args, flags); mode_t mode = static_cast(va_arg (args, int)); va_end (args); @@ -622,12 +622,11 @@ void ftermfreebsdTest::freebsdConsoleTest() setenv ("COLUMNS", "80", 1); setenv ("LINES", "25", 1); - finalcut::FTermData* data; finalcut::FSystem* fsys = new test::FSystemTest(); - finalcut::FTermDetection* term_detection; + finalcut::FTermDetection* term_detection{}; finalcut::FTerm::setFSystem(fsys); std::cout << "\n"; - data = finalcut::FTerm::getFTermData(); + finalcut::FTermData* data = finalcut::FTerm::getFTermData(); auto& encoding_list = data->getEncodingList(); encoding_list["UTF-8"] = finalcut::fc::UTF8; @@ -698,45 +697,46 @@ void ftermfreebsdTest::freebsdConsoleTest() freebsd.setCursorStyle(freebsd.getCursorStyle()); CPPUNIT_ASSERT ( freebsd.getCursorStyle() == finalcut::fc::blink_cursor ); - CPPUNIT_ASSERT ( finalcut::fc::character[2][finalcut::fc::PC] == 21 ); - CPPUNIT_ASSERT ( finalcut::fc::character[3][finalcut::fc::PC] == 8 ); - CPPUNIT_ASSERT ( finalcut::fc::character[4][finalcut::fc::PC] == 10 ); - CPPUNIT_ASSERT ( finalcut::fc::character[5][finalcut::fc::PC] == 19 ); - CPPUNIT_ASSERT ( finalcut::fc::character[6][finalcut::fc::PC] == 18 ); - CPPUNIT_ASSERT ( finalcut::fc::character[8][finalcut::fc::PC] == 22 ); - CPPUNIT_ASSERT ( finalcut::fc::character[9][finalcut::fc::PC] == 24 ); - CPPUNIT_ASSERT ( finalcut::fc::character[10][finalcut::fc::PC] == 25 ); - CPPUNIT_ASSERT ( finalcut::fc::character[11][finalcut::fc::PC] == 26 ); - CPPUNIT_ASSERT ( finalcut::fc::character[12][finalcut::fc::PC] == 27 ); - CPPUNIT_ASSERT ( finalcut::fc::character[23][finalcut::fc::PC] == 4 ); - CPPUNIT_ASSERT ( finalcut::fc::character[25][finalcut::fc::PC] == 4 ); - CPPUNIT_ASSERT ( finalcut::fc::character[26][finalcut::fc::PC] == 4 ); - CPPUNIT_ASSERT ( finalcut::fc::character[57][finalcut::fc::PC] == 16 ); - CPPUNIT_ASSERT ( finalcut::fc::character[58][finalcut::fc::PC] == 17 ); - CPPUNIT_ASSERT ( finalcut::fc::character[59][finalcut::fc::PC] == 16 ); - CPPUNIT_ASSERT ( finalcut::fc::character[60][finalcut::fc::PC] == 17 ); - CPPUNIT_ASSERT ( finalcut::fc::character[105][finalcut::fc::PC] == 4 ); + finalcut::fc::encoding enc = finalcut::fc::PC; + CPPUNIT_ASSERT ( finalcut::fc::character[2][enc] == 21 ); + CPPUNIT_ASSERT ( finalcut::fc::character[3][enc] == 8 ); + CPPUNIT_ASSERT ( finalcut::fc::character[4][enc] == 10 ); + CPPUNIT_ASSERT ( finalcut::fc::character[5][enc] == 19 ); + CPPUNIT_ASSERT ( finalcut::fc::character[6][enc] == 18 ); + CPPUNIT_ASSERT ( finalcut::fc::character[8][enc] == 22 ); + CPPUNIT_ASSERT ( finalcut::fc::character[9][enc] == 24 ); + CPPUNIT_ASSERT ( finalcut::fc::character[10][enc] == 25 ); + CPPUNIT_ASSERT ( finalcut::fc::character[11][enc] == 26 ); + CPPUNIT_ASSERT ( finalcut::fc::character[12][enc] == 27 ); + CPPUNIT_ASSERT ( finalcut::fc::character[23][enc] == 4 ); + CPPUNIT_ASSERT ( finalcut::fc::character[25][enc] == 4 ); + CPPUNIT_ASSERT ( finalcut::fc::character[26][enc] == 4 ); + CPPUNIT_ASSERT ( finalcut::fc::character[57][enc] == 16 ); + CPPUNIT_ASSERT ( finalcut::fc::character[58][enc] == 17 ); + CPPUNIT_ASSERT ( finalcut::fc::character[59][enc] == 16 ); + CPPUNIT_ASSERT ( finalcut::fc::character[60][enc] == 17 ); + CPPUNIT_ASSERT ( finalcut::fc::character[105][enc] == 4 ); freebsd.initCharMap(); - CPPUNIT_ASSERT ( finalcut::fc::character[2][finalcut::fc::PC] == 36 ); - CPPUNIT_ASSERT ( finalcut::fc::character[3][finalcut::fc::PC] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[4][finalcut::fc::PC] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[5][finalcut::fc::PC] == 33 ); - CPPUNIT_ASSERT ( finalcut::fc::character[6][finalcut::fc::PC] == 73 ); - CPPUNIT_ASSERT ( finalcut::fc::character[8][finalcut::fc::PC] == 95 ); - CPPUNIT_ASSERT ( finalcut::fc::character[9][finalcut::fc::PC] == 94 ); - CPPUNIT_ASSERT ( finalcut::fc::character[10][finalcut::fc::PC] == 118 ); - CPPUNIT_ASSERT ( finalcut::fc::character[11][finalcut::fc::PC] == 62 ); - CPPUNIT_ASSERT ( finalcut::fc::character[12][finalcut::fc::PC] == 60 ); - CPPUNIT_ASSERT ( finalcut::fc::character[23][finalcut::fc::PC] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[25][finalcut::fc::PC] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[26][finalcut::fc::PC] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[57][finalcut::fc::PC] == 62 ); - CPPUNIT_ASSERT ( finalcut::fc::character[58][finalcut::fc::PC] == 60 ); - CPPUNIT_ASSERT ( finalcut::fc::character[59][finalcut::fc::PC] == 62 ); - CPPUNIT_ASSERT ( finalcut::fc::character[60][finalcut::fc::PC] == 60 ); - CPPUNIT_ASSERT ( finalcut::fc::character[105][finalcut::fc::PC] == 42 ); + CPPUNIT_ASSERT ( finalcut::fc::character[2][enc] == 36 ); + CPPUNIT_ASSERT ( finalcut::fc::character[3][enc] == 42 ); + CPPUNIT_ASSERT ( finalcut::fc::character[4][enc] == 42 ); + CPPUNIT_ASSERT ( finalcut::fc::character[5][enc] == 33 ); + CPPUNIT_ASSERT ( finalcut::fc::character[6][enc] == 73 ); + CPPUNIT_ASSERT ( finalcut::fc::character[8][enc] == 95 ); + CPPUNIT_ASSERT ( finalcut::fc::character[9][enc] == 94 ); + CPPUNIT_ASSERT ( finalcut::fc::character[10][enc] == 118 ); + CPPUNIT_ASSERT ( finalcut::fc::character[11][enc] == 62 ); + CPPUNIT_ASSERT ( finalcut::fc::character[12][enc] == 60 ); + CPPUNIT_ASSERT ( finalcut::fc::character[23][enc] == 42 ); + CPPUNIT_ASSERT ( finalcut::fc::character[25][enc] == 42 ); + CPPUNIT_ASSERT ( finalcut::fc::character[26][enc] == 42 ); + CPPUNIT_ASSERT ( finalcut::fc::character[57][enc] == 62 ); + CPPUNIT_ASSERT ( finalcut::fc::character[58][enc] == 60 ); + CPPUNIT_ASSERT ( finalcut::fc::character[59][enc] == 62 ); + CPPUNIT_ASSERT ( finalcut::fc::character[60][enc] == 60 ); + CPPUNIT_ASSERT ( finalcut::fc::character[105][enc] == 42 ); term_detection->detect(); diff --git a/test/ftermlinux-test.cpp b/test/ftermlinux-test.cpp index 0f937954..e57fdf4e 100644 --- a/test/ftermlinux-test.cpp +++ b/test/ftermlinux-test.cpp @@ -145,10 +145,10 @@ class FSystemTest : public finalcut::FSystem 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0c, 0x00, 0x0f, 0x08, 0x00 }; - uChar ac_index = 0; - bool palette_addr_source_field = true; - uChar port_3cc = 0x67; // Miscellaneous output - uChar port_3da = 0; // Input status 1 + uChar ac_index{0}; + bool palette_addr_source_field{true}; + uChar port_3cc{0x67}; // Miscellaneous output + uChar port_3da{0}; // Input status 1 static uChar vga8x16[]; static struct unipair unicode_cp437_pairs[]; }; @@ -965,12 +965,12 @@ FSystemTest::rgb FSystemTest::defaultColor[16] // static class attributes //---------------------------------------------------------------------- -FSystemTest::shiftstate FSystemTest::shift_state; -struct console_font_op FSystemTest::terminal_font; -unimapdesc FSystemTest::terminal_unicode_map; -struct fb_var_screeninfo FSystemTest::fb_terminal_info; -struct fb_fix_screeninfo FSystemTest::fb_terminal_fix_info; -bool FSystemTest::vga_port_access = false; +FSystemTest::shiftstate FSystemTest::shift_state{}; +struct console_font_op FSystemTest::terminal_font{}; +unimapdesc FSystemTest::terminal_unicode_map{}; +struct fb_var_screeninfo FSystemTest::fb_terminal_info{}; +struct fb_fix_screeninfo FSystemTest::fb_terminal_fix_info{}; +bool FSystemTest::vga_port_access{false}; // constructors and destructor @@ -1062,10 +1062,10 @@ int FSystemTest::isTTY (int fd) //---------------------------------------------------------------------- int FSystemTest::ioctl (int fd, uLong request, ...) { - va_list args; - void* argp; - std::string req_string; - int ret_val = -1; + va_list args{}; + void* argp{}; + std::string req_string{}; + int ret_val{-1}; va_start (args, request); argp = va_arg (args, void*); @@ -1290,7 +1290,7 @@ int FSystemTest::ioctl (int fd, uLong request, ...) //---------------------------------------------------------------------- int FSystemTest::open (const char* pathname, int flags, ...) { - va_list args; + va_list args{}; va_start (args, flags); mode_t mode = static_cast(va_arg (args, int)); va_end (args); @@ -1518,13 +1518,11 @@ void FTermLinuxTest::classNameTest() //---------------------------------------------------------------------- void FTermLinuxTest::linuxConsoleTest() { - finalcut::FTermData* data; - finalcut::FSystem* fsys; - fsys = new test::FSystemTest(); + finalcut::FSystem* fsys = new test::FSystemTest(); finalcut::FTerm::setFSystem(fsys); - finalcut::FTermDetection* term_detection; + finalcut::FTermDetection* term_detection{}; std::cout << "\n"; - data = finalcut::FTerm::getFTermData(); + finalcut::FTermData* data = finalcut::FTerm::getFTermData(); auto& encoding_list = data->getEncodingList(); encoding_list["UTF-8"] = finalcut::fc::UTF8; @@ -1642,13 +1640,11 @@ void FTermLinuxTest::linuxConsoleTest() //---------------------------------------------------------------------- void FTermLinuxTest::linuxCursorStyleTest() { - finalcut::FTermData* data; - finalcut::FSystem* fsys; - fsys = new test::FSystemTest(); + finalcut::FSystem* fsys = new test::FSystemTest(); finalcut::FTerm::setFSystem(fsys); - finalcut::FTermDetection* term_detection; + finalcut::FTermDetection* term_detection{}; std::cout << "\n"; - data = finalcut::FTerm::getFTermData(); + finalcut::FTermData* data = finalcut::FTerm::getFTermData(); auto& encoding_list = data->getEncodingList(); encoding_list["UTF-8"] = finalcut::fc::UTF8; @@ -1833,13 +1829,11 @@ void FTermLinuxTest::linuxCursorStyleTest() //---------------------------------------------------------------------- void FTermLinuxTest::linuxColorPaletteTest() { - finalcut::FTermData* data; - finalcut::FSystem* fsys; - fsys = new test::FSystemTest(); + finalcut::FSystem* fsys = new test::FSystemTest(); finalcut::FTerm::setFSystem(fsys); - finalcut::FTermDetection* term_detection; + finalcut::FTermDetection* term_detection{}; std::cout << "\n"; - data = finalcut::FTerm::getFTermData(); + finalcut::FTermData* data = finalcut::FTerm::getFTermData(); auto& encoding_list = data->getEncodingList(); encoding_list["UTF-8"] = finalcut::fc::UTF8; @@ -2111,13 +2105,11 @@ void FTermLinuxTest::linuxColorPaletteTest() //---------------------------------------------------------------------- void FTermLinuxTest::linuxFontTest() { - finalcut::FTermData* data; - finalcut::FSystem* fsys; - fsys = new test::FSystemTest(); + finalcut::FSystem* fsys = new test::FSystemTest(); finalcut::FTerm::setFSystem(fsys); - finalcut::FTermDetection* term_detection; + finalcut::FTermDetection* term_detection{}; std::cout << "\n"; - data = finalcut::FTerm::getFTermData(); + finalcut::FTermData* data = finalcut::FTerm::getFTermData(); auto& encoding_list = data->getEncodingList(); encoding_list["UTF-8"] = finalcut::fc::UTF8; @@ -2256,11 +2248,10 @@ void FTermLinuxTest::linuxFontTest() //---------------------------------------------------------------------- void FTermLinuxTest::modifierKeyTest() { - FKey keycode; - FKey mod_keycode; + FKey keycode{}; + FKey mod_keycode{}; const finalcut::FTermLinux linux{}; - finalcut::FSystem* fsys; - fsys = new test::FSystemTest(); + finalcut::FSystem* fsys(new test::FSystemTest()); test::FSystemTest* fsystest = static_cast(fsys); test::FSystemTest::shiftstate& mod_key = fsystest->getShiftState(); diff --git a/test/ftermopenbsd-test.cpp b/test/ftermopenbsd-test.cpp index 63d01a21..0de3f9af 100644 --- a/test/ftermopenbsd-test.cpp +++ b/test/ftermopenbsd-test.cpp @@ -88,8 +88,8 @@ class FSystemTest : public finalcut::FSystem wskbd_bell_data& getBell(); private: - kbd_t kbdencoding = 512; - wskbd_bell_data system_bell; + kbd_t kbdencoding{512}; + wskbd_bell_data system_bell{}; }; @@ -132,10 +132,10 @@ int FSystemTest::isTTY (int fd) //---------------------------------------------------------------------- int FSystemTest::ioctl (int fd, uLong request, ...) { - va_list args; - void* argp; - std::string req_string; - int ret_val = -1; + va_list args{}; + void* argp{}; + std::string req_string{}; + int ret_val{-1}; va_start (args, request); argp = va_arg (args, void*); @@ -218,7 +218,7 @@ int FSystemTest::ioctl (int fd, uLong request, ...) //---------------------------------------------------------------------- int FSystemTest::open (const char* pathname, int flags, ...) { - va_list args; + va_list args{}; va_start (args, flags); mode_t mode = static_cast(va_arg (args, int)); va_end (args); @@ -345,13 +345,11 @@ void ftermopenbsdTest::classNameTest() //---------------------------------------------------------------------- void ftermopenbsdTest::netbsdConsoleTest() { - finalcut::FTermData* data; - finalcut::FSystem* fsys; - fsys = new test::FSystemTest(); + finalcut::FSystem* fsys = new test::FSystemTest(); finalcut::FTerm::setFSystem(fsys); - finalcut::FTermDetection* term_detection; + finalcut::FTermDetection* term_detection{}; std::cout << "\n"; - data = finalcut::FTerm::getFTermData(); + finalcut::FTermData* data = finalcut::FTerm::getFTermData(); auto& encoding_list = data->getEncodingList(); encoding_list["UTF-8"] = finalcut::fc::UTF8; @@ -452,13 +450,11 @@ void ftermopenbsdTest::netbsdConsoleTest() //---------------------------------------------------------------------- void ftermopenbsdTest::openbsdConsoleTest() { - finalcut::FTermData* data; - finalcut::FSystem* fsys; - fsys = new test::FSystemTest(); + finalcut::FSystem* fsys = new test::FSystemTest(); finalcut::FTerm::setFSystem(fsys); - finalcut::FTermDetection* term_detection; + finalcut::FTermDetection* term_detection{}; std::cout << "\n"; - data = finalcut::FTerm::getFTermData(); + finalcut::FTermData* data = finalcut::FTerm::getFTermData(); auto& encoding_list = data->getEncodingList(); encoding_list["UTF-8"] = finalcut::fc::UTF8;