Hello community, here is the log from the commit of package libt3widget for openSUSE:Factory checked in at 2019-12-21 12:32:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libt3widget (Old) and /work/SRC/openSUSE:Factory/.libt3widget.new.6675 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libt3widget" Sat Dec 21 12:32:15 2019 rev:10 rq:758356 version:1.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libt3widget/libt3widget.changes 2019-08-23 11:09:42.354458664 +0200 +++ /work/SRC/openSUSE:Factory/.libt3widget.new.6675/libt3widget.changes 2019-12-21 12:32:44.495402047 +0100 @@ -1,0 +2,14 @@ +Thu Dec 19 23:52:08 UTC 2019 - Jan Engelhardt <[email protected]> + +- Update to release 1.2.0 + * This release provides several new features and bug fixes, + among which: + * Pressing ctrl+backspace will delete the previous word, + * Extra navigation keys (+/- and arrows) for expander widgets. + * Checkboxes can now have a third, indeterminate, state. + * Frame resizing correctly redraws the frame. + * This release changes the selection of binary attributes to + make the distinction between explicitly unset and fallback + from base attribute + +------------------------------------------------------------------- Old: ---- libt3widget-1.0.6.tar.bz2 New: ---- libt3widget-1.2.0.tar.bz2 libt3widget-1.2.0.tar.bz2.sig libt3widget.keyring ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libt3widget.spec ++++++ --- /var/tmp/diff_new_pack.k5O8zN/_old 2019-12-21 12:32:45.799402667 +0100 +++ /var/tmp/diff_new_pack.k5O8zN/_new 2019-12-21 12:32:45.803402668 +0100 @@ -1,7 +1,7 @@ # # spec file for package libt3widget # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,25 +18,27 @@ Name: libt3widget %define lname libt3widget2 -Version: 1.0.6 +Version: 1.2.0 Release: 0 Summary: The Tilde terminal dialog toolkit License: GPL-3.0-only Group: Development/Libraries/C and C++ -Url: https://os.ghalkes.nl/t3/libt3widget.html +URL: https://os.ghalkes.nl/t3/libt3widget.html -#Git-Clone: git://github.com/gphalkes/t3widget +#Git-Clone: https://github.com/gphalkes/t3widget Source: https://os.ghalkes.nl/dist/%name-%version.tar.bz2 +Source2: https://os.ghalkes.nl/dist/%name-%version.tar.bz2.sig +Source3: %name.keyring BuildRequires: c++_compiler BuildRequires: fdupes BuildRequires: gettext-tools BuildRequires: gpm-devel BuildRequires: libtool BuildRequires: libunistring-devel -BuildRequires: pkgconfig +BuildRequires: pkg-config BuildRequires: pkgconfig(libpcre2-8) BuildRequires: pkgconfig(libt3key) >= 0.2.0 -BuildRequires: pkgconfig(libt3window) >= 0.3.1 +BuildRequires: pkgconfig(libt3window) >= 0.4.0 BuildRequires: pkgconfig(libtranscript) >= 0.2.2 BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(xcb) ++++++ libt3widget-1.0.6.tar.bz2 -> libt3widget-1.2.0.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/Changelog new/libt3widget-1.2.0/Changelog --- old/libt3widget-1.0.6/Changelog 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/Changelog 2019-12-03 20:12:13.000000000 +0100 @@ -1,3 +1,35 @@ +Version 1.2.0: + New features: + - The attribute picker dialog distinguishes between explicitly unset and + indeterminate settings. The latter will always fall back to the base + attributes they are combined with. This requires libt3window version 0.4.0 + or later. + +Version 1.1.1: + Bug fixes: + - Display of the indeterminate state of checkbox_t did not work. + - Fix incorrect initialization of edit_window_t::behavior_parameters_t from + edit_window_t::view_parameters_t. + +Version 1.1.0: + New features: + - Ctrl+backspace erases the last word starting from the cursor. + - Expander widgets also expand/collapse on +/- and right/left arrow. + - Menus, including right-click menus, now close when clicking on the border. + - edit_window_t::view_parameters_t is deprecated and replaced by + edit_window_t::behavior_parameters_t. The reason for the replacement is to + make the parameters extensible without breaking ABI compatibility. + - checkbox_t can now operate in tri-state mode. + + Bug fixes + - Handle errors in getcwd more gracefully (i.e. return "/" as current working + directory). + - Make force_redraw for frame_t call widget_t force_redraw as well, to ensure + that the frame_t is redrawn as well. This was very visible when resizing + the file dialogs. + - Calling set_size on edit_window_t now correctly handles nullopt values in + the parameters. + Version 1.0.6: Bug fixes - Search & replace handles zero-width search results from regular expressions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/config.pkg new/libt3widget-1.2.0/config.pkg --- old/libt3widget-1.0.6/config.pkg 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/config.pkg 2019-12-03 20:12:13.000000000 +0100 @@ -146,7 +146,7 @@ return 0; } EOF - pkgconfig libt3window/0.3.1 LIBT3WINDOW test_link_cxx PKGCONFIG_REQUIRES || \ + pkgconfig libt3window/0.4.0 LIBT3WINDOW test_link_cxx PKGCONFIG_REQUIRES || \ error "!! Can not find libt3window. libt3window is required to compile libt3widget." clean_cxx @@ -405,7 +405,7 @@ fi PKGCONFIG_DESC="Dialog toolkit library" - PKGCONFIG_VERSION="1.0.6" + PKGCONFIG_VERSION="1.2.0" PKGCONFIG_URL="http://os.ghalkes.nl/t3/libt3widget.html" PKGCONFIG_CFLAGS="-I\${includedir}/t3/widget" PKGCONFIG_LIBS="-lt3widget" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/colorscheme.cc new/libt3widget-1.2.0/src/colorscheme.cc --- old/libt3widget-1.0.6/src/colorscheme.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/colorscheme.cc 2019-12-03 20:12:13.000000000 +0100 @@ -184,6 +184,10 @@ other attributes, while the full attributes define the complete rendering. In full attributes, the color should not be left unspecified, at least not in the default setting. + + The attributes in this set don't use the T3_ATTR_*_SET bits to allow older software to keep + working without modification or recompilation. They are chosen such that all the highlight + attributes are strictly additive. */ switch (attribute) { case attribute_t::NON_PRINT: @@ -221,9 +225,8 @@ return ensure_color(color_mode ? T3_ATTR_BG_BLACK : T3_ATTR_REVERSE); case attribute_t::META_TEXT: return color_mode ? T3_ATTR_FG_CYAN : T3_ATTR_UNDERLINE; - default: - return 0; } + return 0; } } // namespace t3widget diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.cc new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.cc --- old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.cc 2019-12-03 20:12:13.000000000 +0100 @@ -46,6 +46,20 @@ implementation_t() : fg_picker(nullptr), bg_picker(nullptr), base_attributes(0) {} }; +namespace { + +checkbox_t::TriState attr_to_state(t3_attr_t attr, t3_attr_t bit) { + if (attr & bit) { + return checkbox_t::CHECKED; + } + if (attr & (bit << (T3_ATTR_COLOR_SHIFT + 17))) { + return checkbox_t::UNCHECKED; + } + return checkbox_t::INDERMINATE; +} + +} // namespace + attribute_picker_dialog_t::attribute_picker_dialog_t(optional<std::string> _title, bool with_default) : dialog_t(ATTRIBUTE_PICKER_DIALOG_HEIGHT + 2, ATTRIBUTE_PICKER_DIALOG_WIDTH, std::move(_title), @@ -56,7 +70,7 @@ t3_term_get_caps(&capabilities); - impl->underline_box = emplace_back<checkbox_t>(false); + impl->underline_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED); impl->underline_box->set_position(1, 2); smart_label_t *underline_label = emplace_back<smart_label_t>("_Underline"); underline_label->set_anchor(impl->underline_box, @@ -68,7 +82,7 @@ impl->underline_box->connect_toggled([this] { attribute_changed(); }); impl->underline_box->connect_activate([this] { ok_activate(); }); - impl->bold_box = emplace_back<checkbox_t>(false); + impl->bold_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED); impl->bold_box->set_anchor(impl->underline_box, T3_PARENT(T3_ANCHOR_TOPLEFT) | T3_CHILD(T3_ANCHOR_TOPLEFT)); impl->bold_box->set_position(1, 0); @@ -82,7 +96,7 @@ impl->bold_box->connect_toggled([this] { attribute_changed(); }); impl->bold_box->connect_activate([this] { ok_activate(); }); - impl->dim_box = emplace_back<checkbox_t>(false); + impl->dim_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED); impl->dim_box->set_anchor(impl->bold_box, T3_PARENT(T3_ANCHOR_TOPLEFT) | T3_CHILD(T3_ANCHOR_TOPLEFT)); impl->dim_box->set_position(1, 0); @@ -95,7 +109,7 @@ impl->dim_box->connect_toggled([this] { attribute_changed(); }); impl->dim_box->connect_activate([this] { ok_activate(); }); - impl->reverse_box = emplace_back<checkbox_t>(false); + impl->reverse_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED); impl->reverse_box->set_anchor(impl->dim_box, T3_PARENT(T3_ANCHOR_TOPLEFT) | T3_CHILD(T3_ANCHOR_TOPLEFT)); impl->reverse_box->set_position(1, 0); @@ -109,7 +123,7 @@ impl->reverse_box->connect_toggled([this] { attribute_changed(); }); impl->reverse_box->connect_activate([this] { ok_activate(); }); - impl->blink_box = emplace_back<checkbox_t>(false); + impl->blink_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED); impl->blink_box->set_anchor(impl->reverse_box, T3_PARENT(T3_ANCHOR_TOPLEFT) | T3_CHILD(T3_ANCHOR_TOPLEFT)); impl->blink_box->set_position(1, 0); @@ -220,20 +234,55 @@ t3_attr_t attribute_picker_dialog_t::get_attribute() const { t3_attr_t result = 0; - if (impl->underline_box->get_state()) { - result |= T3_ATTR_UNDERLINE; + switch (impl->underline_box->get_tristate()) { + case checkbox_t::UNCHECKED: + result |= T3_ATTR_UNDERLINE_SET; + break; + case checkbox_t::CHECKED: + result |= T3_ATTR_UNDERLINE | T3_ATTR_UNDERLINE_SET; + break; + default: + break; } - if (impl->bold_box->get_state()) { - result |= T3_ATTR_BOLD; + switch (impl->bold_box->get_tristate()) { + case checkbox_t::UNCHECKED: + result |= T3_ATTR_BOLD_SET; + break; + case checkbox_t::CHECKED: + result |= T3_ATTR_BOLD | T3_ATTR_BOLD_SET; + break; + default: + break; } - if (impl->dim_box->get_state()) { - result |= T3_ATTR_DIM; + switch (impl->dim_box->get_tristate()) { + case checkbox_t::UNCHECKED: + result |= T3_ATTR_DIM_SET; + break; + case checkbox_t::CHECKED: + result |= T3_ATTR_DIM | T3_ATTR_DIM_SET; + break; + default: + break; } - if (impl->blink_box->get_state()) { - result |= T3_ATTR_BLINK; + switch (impl->blink_box->get_tristate()) { + case checkbox_t::UNCHECKED: + result |= T3_ATTR_BLINK_SET; + break; + case checkbox_t::CHECKED: + result |= T3_ATTR_BLINK | T3_ATTR_BLINK_SET; + break; + default: + break; } - if (impl->reverse_box->get_state()) { - result |= T3_ATTR_REVERSE; + switch (impl->reverse_box->get_tristate()) { + case checkbox_t::UNCHECKED: + result |= T3_ATTR_REVERSE_SET; + break; + case checkbox_t::CHECKED: + result |= T3_ATTR_REVERSE | T3_ATTR_REVERSE_SET; + break; + default: + break; } if (impl->fg_picker != nullptr) { result |= impl->fg_picker->get_color(); @@ -245,11 +294,11 @@ } void attribute_picker_dialog_t::set_attribute(t3_attr_t attr) { - impl->underline_box->set_state(attr & T3_ATTR_UNDERLINE); - impl->bold_box->set_state(attr & T3_ATTR_BOLD); - impl->dim_box->set_state(attr & T3_ATTR_DIM); - impl->blink_box->set_state(attr & T3_ATTR_BLINK); - impl->reverse_box->set_state(attr & T3_ATTR_REVERSE); + impl->underline_box->set_tristate(attr_to_state(attr, T3_ATTR_UNDERLINE)); + impl->bold_box->set_tristate(attr_to_state(attr, T3_ATTR_BOLD)); + impl->dim_box->set_tristate(attr_to_state(attr, T3_ATTR_DIM)); + impl->blink_box->set_tristate(attr_to_state(attr, T3_ATTR_BLINK)); + impl->reverse_box->set_tristate(attr_to_state(attr, T3_ATTR_REVERSE)); if (impl->fg_picker != nullptr) { impl->fg_picker->set_color(attr); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.h new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.h --- old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.h 2019-12-03 20:12:13.000000000 +0100 @@ -45,6 +45,7 @@ ~attribute_picker_dialog_t() override; void show() override; + /** Set the value of the attributes to a specific value. */ void set_attribute(t3_attr_t attr); /** Set the base attributes for the attribute picker. @param attr The base attributes to use diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/dialog.cc new/libt3widget-1.2.0/src/dialogs/dialog.cc --- old/libt3widget-1.0.6/src/dialogs/dialog.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/dialogs/dialog.cc 2019-12-03 20:12:13.000000000 +0100 @@ -45,7 +45,8 @@ This constructor should only be called by ::main_window_base_t. */ -dialog_t::dialog_t() : impl(new implementation_t(nullopt)) {} +dialog_t::dialog_t() + : dialog_base_t(impl_alloc<implementation_t>(0)), impl(new_impl<implementation_t>(nullopt)) {} void dialog_t::activate_dialog() { if (!active_dialogs.empty()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/finddialog.cc new/libt3widget-1.2.0/src/dialogs/finddialog.cc --- old/libt3widget-1.0.6/src/dialogs/finddialog.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/dialogs/finddialog.cc 2019-12-03 20:12:13.000000000 +0100 @@ -50,7 +50,8 @@ // FIXME: keep (limited) history find_dialog_t::find_dialog_t(int _state) - : dialog_t(FIND_DIALOG_HEIGHT, FIND_DIALOG_WIDTH, _("Find")), impl(new implementation_t()) { + : dialog_t(FIND_DIALOG_HEIGHT, FIND_DIALOG_WIDTH, _("Find"), impl_alloc<implementation_t>(0)), + impl(new_impl<implementation_t>()) { smart_label_t *find_label = emplace_back<smart_label_t>("Fi_nd", true); find_label->set_position(1, 2); impl->find_line = emplace_back<text_field_t>(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/menupanel.cc new/libt3widget-1.2.0/src/dialogs/menupanel.cc --- old/libt3widget-1.0.6/src/dialogs/menupanel.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/dialogs/menupanel.cc 2019-12-03 20:12:13.000000000 +0100 @@ -125,6 +125,10 @@ } if (event.x < 1 || event.x > window.get_width() - 2 || event.y < 1 || event.y > window.get_height() - 2) { + if (event.type == EMOUSE_BUTTON_PRESS && + (event.button_state & (EMOUSE_BUTTON_LEFT | EMOUSE_BUTTON_RIGHT | EMOUSE_BUTTON_MIDDLE))) { + close(); + } return true; } focus_widget(event.y - 1); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/findcontext.cc new/libt3widget-1.2.0/src/findcontext.cc --- old/libt3widget-1.0.6/src/findcontext.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/findcontext.cc 2019-12-03 20:12:13.000000000 +0100 @@ -196,7 +196,6 @@ } size_t c_size; - const char *c; text_pos_t start = std::max<text_pos_t>(0, result->start.pos); if (static_cast<size_t>(start) > haystack.size()) { @@ -225,7 +224,6 @@ char *c_data = reinterpret_cast<char *>( u8_casefold(reinterpret_cast<const uint8_t *>(substr.data()), substr.size(), nullptr, nullptr, reinterpret_cast<uint8_t *>(folded_.get()), &c_size)); - c = c_data; if (c_data != folded_.get()) { // Previous value of folded will be automatically deleted. folded_.reset(c_data); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/key.cc new/libt3widget-1.2.0/src/key.cc --- old/libt3widget-1.0.6/src/key.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/key.cc 2019-12-03 20:12:13.000000000 +0100 @@ -660,27 +660,27 @@ } } else { + key_t key = separate_keypad ? iter->second : map_kp(iter->second); + for (size_t j = dash; j != std::string::npos && key_node->key[j] != 0; j++) { + switch (key_node->key[j]) { + case 'c': + key |= EKEY_CTRL; + break; + case 'm': + key |= EKEY_META; + break; + case 's': + key |= EKEY_SHIFT; + break; + default: + break; + } + } if (key_node->string[0] != 27) { if (strlen(key_node->string) == 1) { - map_single[static_cast<unsigned char>(key_node->string[0])] = iter->second; + map_single[static_cast<unsigned char>(key_node->string[0])] = key; } } else { - key_t key = separate_keypad ? iter->second : map_kp(iter->second); - for (size_t j = dash; j != std::string::npos && key_node->key[j] != 0; j++) { - switch (key_node->key[j]) { - case 'c': - key |= EKEY_CTRL; - break; - case 'm': - key |= EKEY_META; - break; - case 's': - key |= EKEY_SHIFT; - break; - default: - break; - } - } map[key_node->string] = key; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/main.h new/libt3widget-1.2.0/src/main.h --- old/libt3widget-1.0.6/src/main.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/main.h 2019-12-03 20:12:13.000000000 +0100 @@ -34,7 +34,7 @@ The value 0 is an invalid value which should be replaced by the script that builds the release package. */ -#define T3_WIDGET_VERSION 0x010006 +#define T3_WIDGET_VERSION 0x010200 /** A class representing an error from one of the supporting libraries. */ class T3_WIDGET_API complex_error_t { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/signals.h new/libt3widget-1.2.0/src/signals.h --- old/libt3widget-1.0.6/src/signals.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/signals.h 2019-12-03 20:12:13.000000000 +0100 @@ -68,6 +68,12 @@ connection_t() = default; connection_t(std::shared_ptr<internal::func_ptr_base_t> f) : func(f) {} connection_t(const connection_t &other) : func(other.func) {} + + connection_t &operator=(const connection_t &other) { + func = other.func; + return *this; + } + /// Disconnect the callback from the signal. void disconnect() { if (func) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/textbuffer.cc new/libt3widget-1.2.0/src/textbuffer.cc --- old/libt3widget-1.0.6/src/textbuffer.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/textbuffer.cc 2019-12-03 20:12:13.000000000 +0100 @@ -13,7 +13,6 @@ */ #include <algorithm> #include <cstring> -#include <ext/alloc_traits.h> #include <limits> #include <memory> #include <string> @@ -58,6 +57,8 @@ bool text_buffer_t::backspace_char() { return impl->backspace_char(); } +bool text_buffer_t::backspace_word() { return impl->backspace_word(); } + bool text_buffer_t::is_modified() const { return !impl->undo_list.is_at_mark(); } bool text_buffer_t::merge(bool backspace) { return impl->merge(backspace); } @@ -266,6 +267,25 @@ return false; } cursor.pos = newpos; + cursor.pos = lines[cursor.line]->adjust_position(cursor.pos, 0); + + rewrap_required(rewrap_type_t::REWRAP_LINE_LOCAL, cursor.line, cursor.pos); + + last_undo_position = cursor; + return true; +} + +bool text_buffer_t::implementation_t::backspace_word() { + text_pos_t newpos; + text_line_t *line = lines[cursor.line].get(); + newpos = line->get_previous_word(cursor.pos); + if (newpos < 0) { + newpos = 0; + } + if (!line->backspace_word(cursor.pos, newpos, get_undo(UNDO_BACKSPACE))) { + return false; + } + cursor.pos = newpos; cursor.pos = lines[cursor.line]->adjust_position(cursor.pos, 0); rewrap_required(rewrap_type_t::REWRAP_LINE_LOCAL, cursor.line, cursor.pos); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/textbuffer.h new/libt3widget-1.2.0/src/textbuffer.h --- old/libt3widget-1.0.6/src/textbuffer.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/textbuffer.h 2019-12-03 20:12:13.000000000 +0100 @@ -57,6 +57,7 @@ bool overwrite_char(key_t c); bool delete_char(); bool backspace_char(); + bool backspace_word(); bool merge(bool backspace); bool break_line(const std::string &indent = ""); bool insert_block(const std::string &block); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/textbuffer_impl.h new/libt3widget-1.2.0/src/textbuffer_impl.h --- old/libt3widget-1.0.6/src/textbuffer_impl.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/textbuffer_impl.h 2019-12-03 20:12:13.000000000 +0100 @@ -57,6 +57,7 @@ bool overwrite_char(key_t c); bool delete_char(); bool backspace_char(); + bool backspace_word(); bool merge_internal(text_pos_t line); bool insert_block_internal(text_coordinate_t insert_at, std::unique_ptr<text_line_t> block); void delete_block_internal(text_coordinate_t start, text_coordinate_t end, undo_t *undo); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/textline.cc new/libt3widget-1.2.0/src/textline.cc --- old/libt3widget-1.0.6/src/textline.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/textline.cc 2019-12-03 20:12:13.000000000 +0100 @@ -782,6 +782,35 @@ return insert_char(impl->buffer.size(), c, undo); } +/* Backspace word at 'pos' */ +bool text_line_t::backspace_word(text_pos_t pos, text_pos_t newpos, undo_t *undo) { + text_pos_t oldspace; + + if (pos < 0 || static_cast<size_t>(pos) > impl->buffer.size()) { + return false; + } + + if (newpos < 0 || static_cast<size_t>(newpos) > impl->buffer.size()) { + return false; + } + + if (impl->starts_with_combining && newpos == 0) { + impl->starts_with_combining = false; + } + + oldspace = pos - newpos; + if (undo != nullptr) { + tiny_string_t *undo_text = undo->get_text(); + undo_text->reserve(oldspace); + ASSERT(undo->get_type() == UNDO_BACKSPACE); + undo_text->insert(0, string_view(impl->buffer.data() + newpos, oldspace)); + } + + impl->buffer.erase(newpos, oldspace); + + return true; +} + /* Delete char at 'pos - 1' */ bool text_line_t::backspace_char(text_pos_t pos, undo_t *undo) { if (pos == 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/textline.h new/libt3widget-1.2.0/src/textline.h --- old/libt3widget-1.0.6/src/textline.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/textline.h 2019-12-03 20:12:13.000000000 +0100 @@ -132,6 +132,7 @@ bool delete_char(text_pos_t pos, undo_t *undo); bool append_char(key_t c, undo_t *undo); bool backspace_char(text_pos_t pos, undo_t *undo); + bool backspace_word(text_pos_t pos, text_pos_t newpos, undo_t *undo); text_pos_t adjust_position(text_pos_t pos, int adjust) const; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/util.cc new/libt3widget-1.2.0/src/util.cc --- old/libt3widget-1.0.6/src/util.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/util.cc 2019-12-03 20:12:13.000000000 +0100 @@ -284,30 +284,31 @@ size_t buffer_max = 511; char *buffer = nullptr, *result; + call_on_return_t free_buffer([&] { free(buffer); }); + do { result = reinterpret_cast<char *>(realloc(buffer, buffer_max)); if (result == nullptr) { - free(buffer); throw ENOMEM; } buffer = result; if ((result = getcwd(buffer, buffer_max)) == nullptr) { if (errno != ERANGE) { - int error_save = errno; - free(buffer); - throw error_save; + lprintf("Could not get working directory (returning /): %s\n", strerror(errno)); + return "/"; } if ((static_cast<size_t>(-1)) / 2 < buffer_max) { - free(buffer); throw ENOMEM; } } } while (result == nullptr); - std::string retval(buffer); - free(buffer); - return retval; + if (buffer[0] == '/') { + return buffer; + } else { + return "/"; + } } std::string get_directory(string_view directory) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/button.cc new/libt3widget-1.2.0/src/widgets/button.cc --- old/libt3widget-1.0.6/src/widgets/button.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/button.cc 2019-12-03 20:12:13.000000000 +0100 @@ -69,16 +69,16 @@ break; case EKEY_LEFT: move_focus_left(); - break; + return !impl->has_focus; case EKEY_RIGHT: move_focus_right(); - break; + return !impl->has_focus; case EKEY_UP: move_focus_up(); - break; + return !impl->has_focus; case EKEY_DOWN: move_focus_down(); - break; + return !impl->has_focus; default: return false; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/checkbox.cc new/libt3widget-1.2.0/src/widgets/checkbox.cc --- old/libt3widget-1.0.6/src/widgets/checkbox.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/checkbox.cc 2019-12-03 20:12:13.000000000 +0100 @@ -23,10 +23,15 @@ #include "t3window/window.h" namespace t3widget { +namespace { +const char kStateToChar[] = " X:"; +} struct checkbox_t::implementation_t { - /** Current state (true if checked). */ - bool state; + /** Whether tri-state mode is enabled. */ + bool is_tristate; + /** Current state. */ + TriState state; /** Boolean indicating whether this widget should be drawn as focuessed. */ bool has_focus = false; /** Label associated with this checkbox_t. Used for determining the hotkey. */ @@ -34,41 +39,71 @@ signal_t<> activate; signal_t<> toggled; - implementation_t(bool _state) : state(_state) {} + implementation_t(bool _state) + : is_tristate(false), state(_state ? checkbox_t::CHECKED : checkbox_t::UNCHECKED) {} + implementation_t(TriState _state) : is_tristate(true), state(_state) {} }; -checkbox_t::checkbox_t(bool _state) +checkbox_t::checkbox_t(bool state) : widget_t(1, 3, true, impl_alloc<focus_widget_t::implementation_t>(impl_alloc<implementation_t>(0))), focus_widget_t(this), - impl(new_impl<implementation_t>(_state)) {} + impl(new_impl<implementation_t>(state)) {} + +checkbox_t::checkbox_t(TriState state) + : widget_t(1, 3, true, + impl_alloc<focus_widget_t::implementation_t>(impl_alloc<implementation_t>(0))), + focus_widget_t(this), + impl(new_impl<implementation_t>(state)) {} checkbox_t::~checkbox_t() {} +void checkbox_t::next_state() { + if (impl->is_tristate) { + switch (impl->state) { + case UNCHECKED: + impl->state = CHECKED; + break; + case CHECKED: + impl->state = INDERMINATE; + break; + default: + impl->state = UNCHECKED; + break; + } + } else { + if (impl->state == UNCHECKED) { + impl->state = CHECKED; + } else { + impl->state = UNCHECKED; + } + } + force_redraw(); + impl->toggled(); + update_contents(); +} + bool checkbox_t::process_key(key_t key) { switch (key) { case ' ': case EKEY_HOTKEY: - impl->state ^= true; - force_redraw(); - impl->toggled(); - update_contents(); + next_state(); break; case EKEY_NL: impl->activate(); break; case EKEY_LEFT: move_focus_left(); - break; + return !impl->has_focus; case EKEY_RIGHT: move_focus_right(); - break; + return !impl->has_focus; case EKEY_UP: move_focus_up(); - break; + return !impl->has_focus; case EKEY_DOWN: move_focus_down(); - break; + return !impl->has_focus; default: return false; } @@ -88,8 +123,12 @@ window.set_default_attrs(attributes.dialog); window.set_paint(0, 0); window.addch('[', 0); - window.addch(is_enabled() ? (impl->state ? 'X' : ' ') : '-', - impl->has_focus ? T3_ATTR_REVERSE : 0); + char c = '-'; + if (is_enabled()) { + c = kStateToChar[std::min<int>(impl->state, 2)]; + } + + window.addch(c, impl->has_focus ? T3_ATTR_REVERSE : 0); window.addch(']', 0); } @@ -101,10 +140,10 @@ impl->has_focus = focus; } -bool checkbox_t::get_state() { return impl->state; } +bool checkbox_t::get_state() { return impl->state == CHECKED; } void checkbox_t::set_state(bool _state) { - impl->state = !!_state; + impl->state = _state ? CHECKED : UNCHECKED; force_redraw(); } @@ -127,14 +166,29 @@ bool checkbox_t::process_mouse_event(mouse_event_t event) { if (event.button_state & EMOUSE_CLICKED_LEFT) { - impl->state ^= true; - force_redraw(); - impl->toggled(); - update_contents(); + next_state(); } return true; } +void checkbox_t::set_tristate_mode(bool is_tristate) { + if (impl->is_tristate == is_tristate) { + return; + } + if (impl->is_tristate && impl->state == INDERMINATE) { + impl->state = UNCHECKED; + force_redraw(); + } + impl->is_tristate = is_tristate; +} + +checkbox_t::TriState checkbox_t::get_tristate() const { return impl->state; } + +void checkbox_t::set_tristate(TriState state) { + impl->state = state; + force_redraw(); +} + _T3_WIDGET_IMPL_SIGNAL(checkbox_t, activate) _T3_WIDGET_IMPL_SIGNAL(checkbox_t, toggled) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/checkbox.h new/libt3widget-1.2.0/src/widgets/checkbox.h --- old/libt3widget-1.0.6/src/widgets/checkbox.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/checkbox.h 2019-12-03 20:12:13.000000000 +0100 @@ -33,11 +33,16 @@ single_alloc_pimpl_t<implementation_t> impl; + void next_state(); + public: + /** Enum indicating the different states the checkbox can be in. */ + enum TriState { UNCHECKED, CHECKED, INDERMINATE }; /** Create a new checkbox_t. @param _state The initial state of the checkbox_t. */ - checkbox_t(bool _state = false); + checkbox_t(bool state = false); + checkbox_t(TriState tristate); ~checkbox_t() override; bool process_key(key_t key) override; /** Set the size of this checkbox_t (ignored). @@ -52,13 +57,26 @@ contents will be shown as a dash (-). */ void set_enabled(bool enable) override; - /** Retrieve the current state of the checkbox_t. */ + /** Retrieve the current state of the checkbox_t. + + If the checkbox_t is in tri-state mode and the value is INDETERMINATE, false is returned. */ bool get_state(); /** Set the current state of the checkbox_t. */ void set_state(bool _state); /** Associate this checkbox_t with a smart_label_t. */ void set_label(smart_label_t *_label); + /** Sets whether the checkbox_t should be in tri-state mode. + + When switching the checkbox_t to non-tri-state mode and the value is currently INDETERMINATE, + the value will be set to UNCHECKED. + */ + void set_tristate_mode(bool is_tristate); + /** Retrieve the current state of the checkbox_t. */ + TriState get_tristate() const; + /** Set the current state of the checkbox_t. */ + void set_tristate(TriState state); + /** @fn connection_t connect_activate(std::function<void()> func) Connect a callback to the #activate signal. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/editwindow.cc new/libt3widget-1.2.0/src/widgets/editwindow.cc --- old/libt3widget-1.0.6/src/widgets/editwindow.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/editwindow.cc 2019-12-03 20:12:13.000000000 +0100 @@ -134,6 +134,18 @@ repaint_max = std::numeric_limits<text_pos_t>::max(); /**< Last line to repaint. */ }; +struct edit_window_t::behavior_parameters_t::implementation_t { + text_coordinate_t top_left{0, 0}; + text_pos_t last_set_pos = 0; + int tabsize = 8; + int ins_mode = 0; + wrap_type_t wrap_type = wrap_type_t::NONE; + bool tab_spaces = false; + bool auto_indent = true; + bool indent_aware_home = true; + bool show_tabs = false; +}; + void edit_window_t::init(bool _init) { if (_init) { /* Construct these from t3widget::init, such that the locale is set correctly and @@ -153,11 +165,12 @@ global_find_dialog = nullptr; delete replace_buttons; replace_buttons = nullptr; + delete right_click_menu; + right_click_menu = nullptr; } } -edit_window_t::edit_window_t(text_buffer_t *_text, const view_parameters_t *params) - : impl(new implementation_t()), text(nullptr) { +void edit_window_t::init_instance() { /* Register the unbacked window for mouse events, such that we can get focus if the bottom line is clicked. */ init_unbacked_window(11, 11, true); @@ -183,8 +196,6 @@ impl->scrollbar->connect_clicked(bind_front(&edit_window_t::scrollbar_clicked, this)); impl->scrollbar->connect_dragged(bind_front(&edit_window_t::scrollbar_dragged, this)); - set_text(_text == nullptr ? new text_buffer_t() : _text, params); - impl->screen_pos = 0; impl->focus = false; @@ -192,12 +203,36 @@ impl->autocomplete_panel->connect_activate([this] { autocomplete_activated(); }); } +edit_window_t::edit_window_t(text_buffer_t *_text, const view_parameters_t *params) + : widget_t(impl_alloc<implementation_t>(0)), impl(new_impl<implementation_t>()), text(nullptr) { + init_instance(); + set_text(_text == nullptr ? new text_buffer_t() : _text, params); +} + +edit_window_t::edit_window_t(text_buffer_t *_text, const behavior_parameters_t *params) + : widget_t(impl_alloc<implementation_t>(0)), impl(new_impl<implementation_t>()), text(nullptr) { + init_instance(); + set_text(_text == nullptr ? new text_buffer_t() : _text, params); +} + edit_window_t::~edit_window_t() { delete impl->wrap_info; } void edit_window_t::set_text(text_buffer_t *_text, const view_parameters_t *params) { if (text == _text) { return; } + if (params != nullptr) { + behavior_parameters_t new_params(*params); + set_text(_text, &new_params); + } else { + set_text(_text, static_cast<behavior_parameters_t *>(nullptr)); + } +} + +void edit_window_t::set_text(text_buffer_t *_text, const behavior_parameters_t *params) { + if (text == _text) { + return; + } text = _text; if (params != nullptr) { @@ -219,7 +254,12 @@ bool edit_window_t::set_size(optint height, optint width) { bool result = true; - // FIXME: these int's are optional!!! Take that into account below! + if (!height.is_valid()) { + height = window.get_height(); + } + if (!width.is_valid()) { + width = window.get_width(); + } if (width.value() != window.get_width() || height.value() > window.get_height()) { update_repaint_lines(0, std::numeric_limits<text_pos_t>::max()); @@ -1012,6 +1052,29 @@ impl->last_set_pos = impl->screen_pos; break; } + case EKEY_BS | EKEY_CTRL: + if (text->get_selection_mode() == selection_mode_t::NONE) { + const text_coordinate_t cursor = text->get_cursor(); + if (cursor.pos <= text->get_line_size(cursor.line)) { + if (cursor.pos != 0) { + text->backspace_word(); + update_repaint_lines(cursor.line); + } else if (cursor.line != 0) { + text->merge(true); + update_repaint_lines(cursor.line); + } + } else { + ASSERT(false); + } + ensure_cursor_on_screen(); + impl->last_set_pos = impl->screen_pos; + } else { + delete_selection(); + } + if (impl->autocomplete_panel->is_shown()) { + activate_autocomplete(false); + } + break; case EKEY_BS: if (text->get_selection_mode() == selection_mode_t::NONE) { const text_coordinate_t cursor = text->get_cursor(); @@ -1305,6 +1368,8 @@ case ACTION_PASTE_SELECTION: paste(false); break; + default: + break; } } @@ -1596,6 +1661,15 @@ *params = view_parameters_t(this); } +std::unique_ptr<edit_window_t::behavior_parameters_t> edit_window_t::save_behavior_parameters() { + // This can't use make_unique, as the constructor is private and only this class is a friend. + return wrap_unique(new behavior_parameters_t(*this)); +} + +void edit_window_t::save_behavior_parameters(behavior_parameters_t *params) { + *params = behavior_parameters_t(*this); +} + void edit_window_t::draw_info_window() {} void edit_window_t::set_autocompleter(autocompleter_t *_autocompleter) { @@ -1897,6 +1971,102 @@ } void edit_window_t::view_parameters_t::set_show_tabs(bool _show_tabs) { show_tabs = _show_tabs; } +//====================== behavior_parameters_t ======================== + +edit_window_t::behavior_parameters_t::behavior_parameters_t(const edit_window_t &view) + : impl(new implementation_t) { + impl->top_left = view.impl->top_left; + impl->wrap_type = view.impl->wrap_type; + if (impl->wrap_type != wrap_type_t::NONE) { + impl->top_left.pos = + view.impl->wrap_info->calculate_line_pos(impl->top_left.line, 0, impl->top_left.pos); + } + impl->tabsize = view.impl->tabsize; + impl->tab_spaces = view.impl->tab_spaces; + impl->ins_mode = view.impl->ins_mode; + impl->last_set_pos = view.impl->last_set_pos; + impl->auto_indent = view.impl->auto_indent; + impl->indent_aware_home = view.impl->indent_aware_home; + impl->show_tabs = view.impl->show_tabs; +} + +edit_window_t::behavior_parameters_t::behavior_parameters_t() : impl(new implementation_t) {} + +edit_window_t::behavior_parameters_t::behavior_parameters_t( + const edit_window_t::view_parameters_t ¶ms) + : impl(new implementation_t) { + impl->top_left = params.top_left; + impl->wrap_type = params.wrap_type; + impl->tabsize = params.tabsize; + impl->tab_spaces = params.tab_spaces; + impl->ins_mode = params.ins_mode; + impl->last_set_pos = params.last_set_pos; + impl->auto_indent = params.auto_indent; + impl->indent_aware_home = params.indent_aware_home; + impl->show_tabs = params.show_tabs; +} + +/* Destructor must be defined in the .cc file, because in the .h file the size of implementation_t + is undefined. */ +edit_window_t::behavior_parameters_t::~behavior_parameters_t() {} + +edit_window_t::behavior_parameters_t &edit_window_t::behavior_parameters_t::operator=( + const behavior_parameters_t &other) { + *impl = *other.impl; + return *this; +} + +void edit_window_t::behavior_parameters_t::apply_parameters(edit_window_t *view) const { + view->impl->top_left = impl->top_left; + view->impl->tabsize = impl->tabsize; + view->set_wrap(impl->wrap_type); + /* view->set_wrap will make sure that view->wrap_info is nullptr if + wrap_type != NONE. */ + if (view->impl->wrap_info != nullptr) { + view->impl->wrap_info->set_text_buffer(view->text); + view->impl->top_left.pos = view->impl->wrap_info->find_line(impl->top_left); + } + // the calling function will call ensure_cursor_on_screen + view->impl->tab_spaces = impl->tab_spaces; + view->impl->ins_mode = impl->ins_mode; + view->impl->last_set_pos = impl->last_set_pos; + view->impl->auto_indent = impl->auto_indent; + view->impl->indent_aware_home = impl->indent_aware_home; + view->impl->show_tabs = impl->show_tabs; +} + +void edit_window_t::behavior_parameters_t::set_tabsize(int _tabsize) { impl->tabsize = _tabsize; } +void edit_window_t::behavior_parameters_t::set_wrap(wrap_type_t _wrap_type) { + impl->wrap_type = _wrap_type; +} +void edit_window_t::behavior_parameters_t::set_tab_spaces(bool _tab_spaces) { + impl->tab_spaces = _tab_spaces; +} +void edit_window_t::behavior_parameters_t::set_auto_indent(bool _auto_indent) { + impl->auto_indent = _auto_indent; +} +void edit_window_t::behavior_parameters_t::set_indent_aware_home(bool _indent_aware_home) { + impl->indent_aware_home = _indent_aware_home; +} +void edit_window_t::behavior_parameters_t::set_show_tabs(bool _show_tabs) { + impl->show_tabs = _show_tabs; +} +void edit_window_t::behavior_parameters_t::set_top_left(text_coordinate_t pos) { + impl->top_left = pos; +} + +int edit_window_t::behavior_parameters_t::get_tabsize() const { return impl->tabsize; } +wrap_type_t edit_window_t::behavior_parameters_t::get_wrap_type() const { return impl->wrap_type; } +bool edit_window_t::behavior_parameters_t::get_tab_spaces() const { return impl->tab_spaces; } +bool edit_window_t::behavior_parameters_t::get_auto_indent() const { return impl->auto_indent; } +bool edit_window_t::behavior_parameters_t::get_indent_aware_home() const { + return impl->indent_aware_home; +} +bool edit_window_t::behavior_parameters_t::get_show_tabs() const { return impl->show_tabs; } +text_coordinate_t edit_window_t::behavior_parameters_t::get_top_left() const { + return impl->top_left; +} + //====================== autocomplete_panel_t ======================== edit_window_t::autocomplete_panel_t::autocomplete_panel_t(edit_window_t *parent) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/editwindow.h new/libt3widget-1.2.0/src/widgets/editwindow.h --- old/libt3widget-1.0.6/src/widgets/editwindow.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/editwindow.h 2019-12-03 20:12:13.000000000 +0100 @@ -25,7 +25,6 @@ #include <t3widget/autocompleter.h> #include <t3widget/dialogs/menupanel.h> -#include <t3widget/dialogs/popup.h> #include <t3widget/interfaces.h> #include <t3widget/key.h> #include <t3widget/key_binding.h> @@ -116,6 +115,12 @@ void right_click_menu_activated(int action); + /** Internal function for initializing an instance. + + Called from the constructors to do the part of the work that is the common between them. + */ + void init_instance(); + protected: text_buffer_t *text; /**< Buffer holding the text currently displayed. */ t3window::window_t info_window; /**< Window for other information, such as buffer name. */ @@ -150,12 +155,20 @@ public: class T3_WIDGET_API view_parameters_t; + class T3_WIDGET_API behavior_parameters_t; + + /** Create a new edit_window_t. + @param _text The text to display in the edit_window_t. + @param params The view parameters to set. + @deprecated Use the constructor taking a ::edit_window_t::behavior_parameters_t instead. + */ + edit_window_t(text_buffer_t *_text, const view_parameters_t *params); /** Create a new edit_window_t. @param _text The text to display in the edit_window_t. @param params The view parameters to set. */ - edit_window_t(text_buffer_t *_text = nullptr, const view_parameters_t *params = nullptr); + edit_window_t(text_buffer_t *_text = nullptr, const behavior_parameters_t *params = nullptr); ~edit_window_t() override; bool process_key(key_t key) override; bool set_size(optint height, optint width) override; @@ -173,8 +186,17 @@ get_text to retrieve the current text_buffer_t before calling this function to make sure you have a reference to the current buffer that you can use to delete the old text_buffer_t. + + @deprecated Use the overload taking a ::edit_window_t::behavior_parameters_t instead. */ - void set_text(text_buffer_t *_text, const view_parameters_t *params = nullptr); + void set_text(text_buffer_t *_text, const view_parameters_t *params); + /** Set the text to display. + The previously displayed text will be replaced, without deleting. Use + get_text to retrieve the current text_buffer_t before calling this + function to make sure you have a reference to the current buffer that + you can use to delete the old text_buffer_t. + */ + void set_text(text_buffer_t *_text, const behavior_parameters_t *params = nullptr); /** Get the text currently displayed. */ text_buffer_t *get_text() const; /** Apply the undo action. */ @@ -253,11 +275,20 @@ /** Get show tabs. */ bool get_show_tabs() const; - /** Save the current view parameters, to allow them to be restored later. */ + /** Save the current view parameters, to allow them to be restored later. + @deprecated Use ::edit_window_t::save_behavior_parameters instead. + */ std::unique_ptr<edit_window_t::view_parameters_t> save_view_parameters(); - /** Save the current view parameters, to allow them to be restored later. */ + /** Save the current view parameters, to allow them to be restored later. + @deprecated Use ::edit_window_t::save_behavior_parameters instead. + */ void save_view_parameters(view_parameters_t *params); + /** Save the current view parameters, to allow them to be restored later. */ + std::unique_ptr<edit_window_t::behavior_parameters_t> save_behavior_parameters(); + /** Save the current view parameters, to allow them to be restored later. */ + void save_behavior_parameters(behavior_parameters_t *params); + /** Set the autocompleter to use. */ void set_autocompleter(autocompleter_t *_autocompleter); /** Perform autocompletion, or pop-up autocompletion choice menu. */ @@ -271,6 +302,10 @@ #undef _T3_ACTION_FILE }; +/** A (deprecated) class to hold the parameters of an edit window. + + @deprecated Use ::edit_window_t::behavior_parameters_t instead. +*/ class T3_WIDGET_API edit_window_t::view_parameters_t { friend class edit_window_t; @@ -298,5 +333,38 @@ void set_show_tabs(bool _show_tabs); }; +class T3_WIDGET_API edit_window_t::behavior_parameters_t { + friend class edit_window_t; + + private: + struct T3_WIDGET_LOCAL implementation_t; + pimpl_t<implementation_t> impl; + + behavior_parameters_t(const edit_window_t &view); + behavior_parameters_t(const edit_window_t::view_parameters_t ¶ms); + void apply_parameters(edit_window_t *view) const; + + public: + behavior_parameters_t(); + ~behavior_parameters_t(); + behavior_parameters_t &operator=(const behavior_parameters_t &other); + + void set_tabsize(int _tabsize); + void set_wrap(wrap_type_t _wrap_type); + void set_tab_spaces(bool _tab_spaces); + void set_auto_indent(bool _auto_indent); + void set_indent_aware_home(bool _indent_aware_home); + void set_show_tabs(bool _show_tabs); + void set_top_left(text_coordinate_t pos); + + int get_tabsize() const; + wrap_type_t get_wrap_type() const; + bool get_tab_spaces() const; + bool get_auto_indent() const; + bool get_indent_aware_home() const; + bool get_show_tabs() const; + text_coordinate_t get_top_left() const; +}; + } // namespace t3widget #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/expander.cc new/libt3widget-1.2.0/src/widgets/expander.cc --- old/libt3widget-1.0.6/src/widgets/expander.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/expander.cc 2019-12-03 20:12:13.000000000 +0100 @@ -66,9 +66,40 @@ force_redraw(); } +void expander_t::expand() { + if (!impl->child) { + return; + } + + impl->child->show(); + impl->is_expanded = true; + window.resize(impl->full_height, window.get_width()); + force_redraw(); + if (impl->focus == FOCUS_SELF && impl->child != nullptr && impl->child->accepts_focus()) { + impl->focus = FOCUS_CHILD; + impl->child->set_focus(window_component_t::FOCUS_SET); + } + impl->expanded(true); +} + +void expander_t::collapse() { + if (impl->child != nullptr) { + impl->child->hide(); + } + if (impl->focus == FOCUS_CHILD) { + if (impl->child != nullptr) { + impl->child->set_focus(window_component_t::FOCUS_OUT); + } + impl->focus = FOCUS_SELF; + } + window.resize(1, window.get_width()); + impl->is_expanded = false; + force_redraw(); + impl->expanded(false); +} + void expander_t::set_child(std::unique_ptr<t3widget::widget_t> _child) { focus_widget_t *focus_child; - /* FIXME: connect to move_focus_XXX events. (requires dynamic_cast'ing to focus_widget_t) */ if (impl->child != nullptr) { unset_widget_parent(impl->child.get()); impl->move_up_connection.disconnect(); @@ -119,25 +150,11 @@ force_redraw(); } -void expander_t::set_expanded(bool expand) { - if (!expand && impl->is_expanded) { - if (impl->focus == FOCUS_CHILD) { - impl->child->set_focus(window_component_t::FOCUS_OUT); - impl->focus = FOCUS_SELF; - } - if (impl->child != nullptr) { - impl->child->hide(); - } - impl->is_expanded = false; - window.resize(1, window.get_width()); - force_redraw(); - impl->expanded(false); - } else if (expand && !impl->is_expanded && impl->child != nullptr) { - impl->child->show(); - impl->is_expanded = true; - window.resize(impl->full_height, window.get_width()); - force_redraw(); - impl->expanded(true); +void expander_t::set_expanded(bool expanded) { + if (!expanded && impl->is_expanded) { + collapse(); + } else if (expanded && !impl->is_expanded) { + expand(); } } @@ -153,41 +170,52 @@ return true; } else if (key == EKEY_DOWN && !impl->is_expanded) { move_focus_down(); + return impl->focus == FOCUS_NONE; } else if (key == EKEY_UP) { move_focus_up(); + return impl->focus == FOCUS_NONE; } else if (key == EKEY_RIGHT) { move_focus_right(); + if (impl->focus == FOCUS_SELF) { + expand(); + } + return impl->focus == FOCUS_NONE; } else if (key == EKEY_LEFT) { move_focus_left(); + if (impl->focus == FOCUS_SELF) { + collapse(); + } + return impl->focus == FOCUS_NONE; } else if (key == ' ' || key == EKEY_NL || key == EKEY_HOTKEY) { - if (!impl->is_expanded && impl->child != nullptr) { - window.resize(impl->full_height, window.get_width()); - impl->is_expanded = true; - force_redraw(); - impl->child->show(); - if (impl->child->accepts_focus()) { - impl->focus = FOCUS_CHILD; - impl->child->set_focus(window_component_t::FOCUS_SET); - } - impl->expanded(true); - } else if (impl->is_expanded) { - if (impl->child != nullptr) { - impl->child->hide(); - } - window.resize(1, window.get_width()); - impl->is_expanded = false; - force_redraw(); - impl->expanded(false); + if (impl->is_expanded) { + collapse(); + } else { + expand(); } return true; + } else if (key == '+' && !impl->is_expanded) { + expand(); + return true; + } else if (key == '-' && impl->is_expanded) { + collapse(); + return true; } } else if (impl->focus == FOCUS_CHILD) { bool result = impl->child->process_key(key); - if (!result && key == (EKEY_SHIFT | '\t')) { - impl->focus = FOCUS_SELF; - result = true; - impl->child->set_focus(window_component_t::FOCUS_OUT); - force_redraw(); + if (!result) { + if (key == (EKEY_SHIFT | '\t')) { + impl->focus = FOCUS_SELF; + result = true; + impl->child->set_focus(window_component_t::FOCUS_OUT); + force_redraw(); + return true; + } else if (key == '-') { + collapse(); + return true; + } else if (impl->focus == FOCUS_CHILD && key == EKEY_LEFT) { + collapse(); + return true; + } } return result; } @@ -210,21 +238,20 @@ impl->label.draw(&impl->symbol_window, 0, impl->focus == FOCUS_SELF); } -void expander_t::set_focus(focus_t _focus) { - if (_focus == window_component_t::FOCUS_OUT) { +void expander_t::set_focus(focus_t focus) { + if (focus == window_component_t::FOCUS_OUT) { if (impl->focus == FOCUS_CHILD && impl->child != nullptr) { impl->child->set_focus(window_component_t::FOCUS_OUT); } impl->last_focus = impl->focus; impl->focus = FOCUS_NONE; - } else if (_focus == window_component_t::FOCUS_SET || - _focus == window_component_t::FOCUS_IN_FWD || - (_focus == window_component_t::FOCUS_REVERT && impl->last_focus == FOCUS_SELF) || + } else if (focus == window_component_t::FOCUS_SET || focus == window_component_t::FOCUS_IN_FWD || + (focus == window_component_t::FOCUS_REVERT && impl->last_focus == FOCUS_SELF) || impl->child == nullptr || !impl->is_expanded) { impl->focus = FOCUS_SELF; } else { impl->focus = FOCUS_CHILD; - impl->child->set_focus(_focus); + impl->child->set_focus(focus); } force_redraw(); } @@ -307,26 +334,12 @@ bool expander_t::process_mouse_event(mouse_event_t event) { if (event.button_state & EMOUSE_CLICKED_LEFT) { - if (!impl->is_expanded && impl->child != nullptr) { - window.resize(impl->full_height, window.get_width()); - impl->is_expanded = true; - force_redraw(); - impl->child->show(); - impl->expanded(true); - if (impl->focus == FOCUS_SELF) { - impl->focus = FOCUS_CHILD; - impl->child->set_focus(window_component_t::FOCUS_SET); - } - } else if (impl->is_expanded) { + if (impl->is_expanded) { /* No need to handle impl->focus, because we got a set_focus(SET) event before this call anyway. */ - if (impl->child != nullptr) { - impl->child->hide(); - } - window.resize(1, window.get_width()); - impl->is_expanded = false; - force_redraw(); - impl->expanded(false); + collapse(); + } else { + expand(); } } return true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/expander.h new/libt3widget-1.2.0/src/widgets/expander.h --- old/libt3widget-1.0.6/src/widgets/expander.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/expander.h 2019-12-03 20:12:13.000000000 +0100 @@ -42,6 +42,8 @@ single_alloc_pimpl_t<implementation_t> impl; void focus_up_from_child(); + void expand(); + void collapse(); public: /** Create a new expander_t. @@ -70,7 +72,7 @@ bool process_key(key_t key) override; void update_contents() override; - void set_focus(focus_t _focus) override; + void set_focus(focus_t focus) override; bool set_size(optint height, optint width) override; bool is_hotkey(key_t key) const override; void set_enabled(bool enable) override; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/frame.cc new/libt3widget-1.2.0/src/widgets/frame.cc --- old/libt3widget-1.0.6/src/widgets/frame.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/frame.cc 2019-12-03 20:12:13.000000000 +0100 @@ -120,6 +120,7 @@ } } void frame_t::force_redraw() { + widget_t::force_redraw(); if (impl->child != nullptr) { impl->child->force_redraw(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/textfield.cc new/libt3widget-1.2.0/src/widgets/textfield.cc --- old/libt3widget-1.0.6/src/widgets/textfield.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/textfield.cc 2019-12-03 20:12:13.000000000 +0100 @@ -222,6 +222,22 @@ case EKEY_UP: move_focus_up(); break; + case EKEY_BS | EKEY_CTRL: + if (impl->selection_mode != selection_mode_t::NONE) { + delete_selection(false); + } else if (impl->pos > 0) { + text_pos_t newpos = impl->line->get_previous_word(impl->pos); + if(newpos < 0) { + newpos = 0; + } + if (impl->line->backspace_word(impl->pos, newpos, nullptr)) { + impl->pos = newpos; + ensure_cursor_on_screen(); + force_redraw(); + impl->edited = true; + } + } + break; case EKEY_BS: if (impl->selection_mode != selection_mode_t::NONE) { delete_selection(false); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/widget.h new/libt3widget-1.2.0/src/widgets/widget.h --- old/libt3widget-1.0.6/src/widgets/widget.h 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/widgets/widget.h 2019-12-03 20:12:13.000000000 +0100 @@ -112,9 +112,16 @@ /** Emit signal when the user pressed the down arrow key and focus should move. */ void move_focus_down() const; + /** Get a function that will trigger the move_focus_left signal, for conneting to another signal. + */ std::function<void()> get_move_focus_left_trigger() const; + /** Get a function that will trigger the move_focus_right signal, for conneting to another signal. + */ std::function<void()> get_move_focus_right_trigger() const; + /** Get a function that will trigger the move_focus_up signal, for conneting to another signal. */ std::function<void()> get_move_focus_up_trigger() const; + /** Get a function that will trigger the move_focus_down signal, for conneting to another signal. + */ std::function<void()> get_move_focus_down_trigger() const; struct T3_WIDGET_LOCAL implementation_t; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libt3widget-1.0.6/src/x11.cc new/libt3widget-1.2.0/src/x11.cc --- old/libt3widget-1.0.6/src/x11.cc 2019-05-05 10:23:54.000000000 +0200 +++ new/libt3widget-1.2.0/src/x11.cc 2019-12-03 20:12:13.000000000 +0100 @@ -108,7 +108,9 @@ } void send_wakeup() { - char data; + /* The actual data is irrelevant here, but to prevent warnings about uninitialized data, this + is still initialized here. */ + char data = 0; nosig_write(wakeup_pipe[1], &data, 1); }
