]> git.lyx.org Git - features.git/commitdiff
Give textstyle-apply a history
authorJuergen Spitzmueller <spitz@lyx.org>
Wed, 26 Dec 2018 14:46:14 +0000 (15:46 +0100)
committerJuergen Spitzmueller <spitz@lyx.org>
Wed, 26 Dec 2018 14:46:14 +0000 (15:46 +0100)
The last 20 applications are saved now and accessible both via the lfun
(textstyle-apply n) and the toolbar (via button menu)

Fixes: #7133
This also changes the default icon and toolbar position of the action,
as requested in #11427

14 files changed:
lib/Makefile.am
lib/images/classic/dynamic-freefonts.png [new file with mode: 0644]
lib/images/dynamic-freefonts.svgz [new file with mode: 0644]
lib/images/oxygen/dynamic-freefonts.svgz [new file with mode: 0644]
lib/images/textstyle-apply.svgz
lib/ui/stdtoolbars.inc
src/Font.cpp
src/Font.h
src/LyXAction.cpp
src/Text.h
src/Text3.cpp
src/frontends/qt4/GuiFontLoader.cpp
src/frontends/qt4/GuiToolbar.cpp
src/frontends/qt4/GuiToolbar.h

index 3816d5c7279e763d19a0056a372e20dac6558efa..032103e2abb5df9bb7865ed434f4f872be163a30 100644 (file)
@@ -473,6 +473,7 @@ dist_images_DATA1X = \
        images/down.svgz \
        images/dynamic-char-styles.svgz \
        images/dynamic-custom-insets.svgz \
+       images/dynamic-freefonts.svgz \
        images/editclear.svgz \
        images/emblem-readonly.svgz \
        images/emblem-shellescape.svgz \
@@ -1759,6 +1760,7 @@ dist_imagesoxygen_DATA1X = \
        images/oxygen/dialog-toggle_toc.svgz \
        images/oxygen/dynamic-char-styles.svgz \
        images/oxygen/dynamic-custom-insets.svgz \
+       images/oxygen/dynamic-freefonts.svgz \
        images/oxygen/down.svgz \
        images/oxygen/editclear.svgz \
        images/oxygen/ert-insert.svgz \
@@ -1965,6 +1967,7 @@ dist_imagesclassic_DATA = \
        images/classic/dialog-show_vclog.png  \
        images/classic/dialog-toggle_findreplaceadv.png  \
        images/classic/dialog-toggle_toc.png  \
+       images/classic/dynamic-freefonts.png \
        images/classic/down.png  \
        images/classic/ert-insert.png  \
        images/classic/file-open.png  \
diff --git a/lib/images/classic/dynamic-freefonts.png b/lib/images/classic/dynamic-freefonts.png
new file mode 100644 (file)
index 0000000..a63ad1d
Binary files /dev/null and b/lib/images/classic/dynamic-freefonts.png differ
diff --git a/lib/images/dynamic-freefonts.svgz b/lib/images/dynamic-freefonts.svgz
new file mode 100644 (file)
index 0000000..5830eef
Binary files /dev/null and b/lib/images/dynamic-freefonts.svgz differ
diff --git a/lib/images/oxygen/dynamic-freefonts.svgz b/lib/images/oxygen/dynamic-freefonts.svgz
new file mode 100644 (file)
index 0000000..7a7ffd0
Binary files /dev/null and b/lib/images/oxygen/dynamic-freefonts.svgz differ
index 1a037d49f14e228f0625ab36dc9fcb8adc8eef0f..5830eefb90eb662cebf2f99d6c3dff7ba55e6688 100644 (file)
Binary files a/lib/images/textstyle-apply.svgz and b/lib/images/textstyle-apply.svgz differ
index e0666f0b1343f622462c54cb1f38ad90f0b9111d..412d5647f8577d70ff86fa67015529ea3a4285ab 100644 (file)
@@ -87,7 +87,6 @@ ToolbarSet
                Item "Toggle emphasis" "font-emph"
                Item "Toggle noun" "font-noun"
                DynamicMenu "dynamic-char-styles" "Custom text styles"
-               Item "Apply last text properties" "textstyle-apply"
                Separator
                Item "Insert math" "math-mode on"
                Item "Insert graphics" "dialog-show-new-inset graphics"
@@ -139,6 +138,7 @@ ToolbarSet
                Item "Include file" "dialog-show-new-inset include"
                Separator
                Item "Text properties" "dialog-show character"
+               DynamicMenu "dynamic-freefonts" "Apply recent text properties"
                Item "Paragraph settings" "layout-paragraph"
                Item "Thesaurus" "thesaurus-entry"
        End
index ea31f40b0b7fbca9e203bb50acf51e4d12613021..bb0b54805b0508835e17b1c98b325c7bd01dc8cf 100644 (file)
@@ -143,41 +143,41 @@ void Font::update(Font const & newfont,
 }
 
 
-docstring const stateText(FontInfo const & f)
+docstring const stateText(FontInfo const & f, bool const terse)
 {
        odocstringstream os;
-       if (f.family() != INHERIT_FAMILY)
+       if (f.family() != INHERIT_FAMILY && (!terse || f.family() != IGNORE_FAMILY))
                os << _(GUIFamilyNames[f.family()]) << ", ";
-       if (f.series() != INHERIT_SERIES)
+       if (f.series() != INHERIT_SERIES && (!terse || f.series() != IGNORE_SERIES))
                os << _(GUISeriesNames[f.series()]) << ", ";
-       if (f.shape() != INHERIT_SHAPE)
+       if (f.shape() != INHERIT_SHAPE && (!terse || f.shape() != IGNORE_SHAPE))
                os << _(GUIShapeNames[f.shape()]) << ", ";
-       if (f.size() != FONT_SIZE_INHERIT)
+       if (f.size() != FONT_SIZE_INHERIT && (!terse || f.size() != FONT_SIZE_IGNORE))
                os << _(GUISizeNames[f.size()]) << ", ";
-       if (f.color() != Color_inherit)
+       if (f.color() != Color_inherit && (!terse || f.color() != Color_ignore))
                os << lcolor.getGUIName(f.color()) << ", ";
        // FIXME: uncomment this when we support background.
        //if (f.background() != Color_inherit)
        //      os << lcolor.getGUIName(f.background()) << ", ";
-       if (f.emph() != FONT_INHERIT)
+       if (f.emph() != FONT_INHERIT && (!terse || f.emph() != FONT_IGNORE))
                os << bformat(_("Emphasis %1$s, "),
                              _(GUIMiscNames[f.emph()]));
-       if (f.underbar() != FONT_INHERIT)
+       if (f.underbar() != FONT_INHERIT && (!terse || f.underbar() == FONT_ON))
                os << bformat(_("Underline %1$s, "),
                              _(GUIMiscNames[f.underbar()]));
-       if (f.strikeout() != FONT_INHERIT)
-               os << bformat(_("Strike out %1$s, "),
-                             _(GUIMiscNames[f.strikeout()]));
-       if (f.xout() != FONT_INHERIT)
-               os << bformat(_("Cross out %1$s, "),
-                             _(GUIMiscNames[f.xout()]));
-       if (f.uuline() != FONT_INHERIT)
+       if (f.uuline() != FONT_INHERIT && (!terse || f.uuline() == FONT_ON))
                os << bformat(_("Double underline %1$s, "),
                              _(GUIMiscNames[f.uuline()]));
-       if (f.uwave() != FONT_INHERIT)
+       if (f.uwave() != FONT_INHERIT && (!terse || f.uwave() == FONT_ON))
                os << bformat(_("Wavy underline %1$s, "),
                              _(GUIMiscNames[f.uwave()]));
-       if (f.noun() != FONT_INHERIT)
+       if (f.strikeout() != FONT_INHERIT && (!terse || f.strikeout() == FONT_ON))
+               os << bformat(_("Strike out %1$s, "),
+                             _(GUIMiscNames[f.strikeout()]));
+       if (f.xout() != FONT_INHERIT && (!terse || f.strikeout() == FONT_ON))
+               os << bformat(_("Cross out %1$s, "),
+                             _(GUIMiscNames[f.xout()]));
+       if (f.noun() != FONT_INHERIT && (!terse || f.noun() != FONT_IGNORE))
                os << bformat(_("Noun %1$s, "),
                              _(GUIMiscNames[f.noun()]));
        if (f == inherit_font)
@@ -187,11 +187,12 @@ docstring const stateText(FontInfo const & f)
 }
 
 
-docstring const Font::stateText(BufferParams * params) const
+docstring const Font::stateText(BufferParams * params, bool const terse) const
 {
        odocstringstream os;
-       os << lyx::stateText(bits_);
-       if (!params || (language() != params->language)) {
+       os << lyx::stateText(bits_, terse);
+       if ((!params || (language() != params->language))
+           && (!terse || language() != ignore_language)) {
                // reset_language is a null pointer!
                os << bformat(_("Language: %1$s, "),
                              (language() == reset_language) ? _("Default")
index 9ec853d53387b4aacc2370ebefa3ea542913c0e2..226ad261997731041c0a77ec118e97472fe80518 100644 (file)
@@ -90,7 +90,7 @@ public:
 
 
        /// Build GUI description of font state
-       docstring const stateText(BufferParams * params) const;
+       docstring const stateText(BufferParams * params, bool const terse = false) const;
 
        ///
        void validate(LaTeXFeatures & features) const;
index f5ed3f87873f5c803a5ac5177db75c7434808d85..6d3175222b26561dea7575b4a3bd3a06ba2ee7f8 100644 (file)
@@ -3830,8 +3830,10 @@ void LyXAction::init()
 
 /*!
  * \var lyx::FuncCode lyx::LFUN_TEXTSTYLE_APPLY
- * \li Action: Toggle user-defined (=last-time used) text style.
- * \li Notion: This style is set via #LFUN_TEXTSTYLE_UPDATE, which is
+ * \li Action: Apply last used text properties.
+ * \li Syntax: textstyle-apply [<NUM>]
+ * \li Params: <NUM>: number of the selection in the internal freefonts stack to be applied.
+ * \li Notion: These properties are stored via #LFUN_TEXTSTYLE_UPDATE, which is
                automatically triggered when using Text Style dialog.
  * \li Syntax: textstyle-apply
  * \li Origin: leeming, 12 Mar 2003
index b54277beefa3069b5d676fc5cb94d934e5cfd9cd..054b6f6ee4f3ca0c527248c58a768c61ad2a3279 100644 (file)
@@ -109,6 +109,8 @@ public:
 
        ///
        void toggleFree(Cursor & cur, Font const &, bool toggleall = false);
+       /// Stack to save recent text propterty applications
+       std::vector<docstring> getFreeFonts() const;
 
        /// ???
        /// FIXME: replace Cursor with DocIterator.
index 45eb8155f2780dad55aa5875ea7da0c1c65df382..9dce236a41fcdb1d2480847f661951ede252472f 100644 (file)
@@ -72,6 +72,7 @@
 #include "support/debug.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
+#include "support/limited_stack.h"
 #include "support/lstrings.h"
 #include "support/lyxalgo.h"
 #include "support/lyxtime.h"
@@ -105,7 +106,8 @@ using cap::pasteSimpleText;
 using frontend::Clipboard;
 
 // globals...
-static Font freefont(ignore_font, ignore_language);
+typedef limited_stack<pair<docstring, Font>> FontStack;
+static FontStack freeFonts(15);
 static bool toggleall = false;
 
 static void toggleAndShow(Cursor & cur, Text * text,
@@ -2364,10 +2366,26 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_TEXTSTYLE_APPLY:
-               toggleAndShow(cur, this, freefont, toggleall);
-               cur.message(_("Character set"));
+       case LFUN_TEXTSTYLE_APPLY: {
+               unsigned int num = 0;
+               string const arg = to_utf8(cmd.argument());
+               // Argument?
+               if (!arg.empty()) {
+                       if (isStrUnsignedInt(arg)) {
+                               num = convert<uint>(arg);
+                               if (num >= freeFonts.size()) {
+                                       cur.message(_("Invalid argument (number exceeds stack size)!"));
+                                       break;
+                               }
+                       } else {
+                               cur.message(_("Invalid argument (must be a positive number)!"));
+                               break;
+                       }
+               }
+               toggleAndShow(cur, this, freeFonts[num].second, toggleall);
+               cur.message(bformat(_("Text properties applied: %1$s"), freeFonts[num].first));
                break;
+       }
 
        // Set the freefont using the contents of \param data dispatched from
        // the frontends and apply it at the current cursor location.
@@ -2375,17 +2393,17 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                Font font;
                bool toggle;
                if (font.fromString(to_utf8(cmd.argument()), toggle)) {
-                       freefont = font;
+                       docstring const props = font.stateText(&bv->buffer().params(), true);
+                       freeFonts.push(make_pair(props, font));
                        toggleall = toggle;
-                       toggleAndShow(cur, this, freefont, toggleall);
+                       toggleAndShow(cur, this, font, toggleall);
                        // We need a buffer update if we change the language
                        // of an info inset
                        if (cur.insetInSelection(INFO_CODE))
                                cur.forceBufferUpdate();
-                       cur.message(_("Character set"));
-               } else {
-                       lyxerr << "Argument not ok";
-               }
+                       cur.message(bformat(_("Text properties applied: %1$s"), props));
+               } else
+                       LYXERR0("Invalid argument of textstyle-update");
                break;
        }
 
@@ -3378,11 +3396,14 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_FONT_CROSSOUT:
        case LFUN_FONT_UNDERUNDERLINE:
        case LFUN_FONT_UNDERWAVE:
-       case LFUN_TEXTSTYLE_APPLY:
        case LFUN_TEXTSTYLE_UPDATE:
                enable = !cur.paragraph().isPassThru();
                break;
 
+       case LFUN_TEXTSTYLE_APPLY:
+               enable = !freeFonts.empty();
+               break;
+
        case LFUN_WORD_DELETE_FORWARD:
        case LFUN_WORD_DELETE_BACKWARD:
        case LFUN_LINE_DELETE_FORWARD:
@@ -3506,4 +3527,19 @@ bool Text::inDescriptionItem(Cursor & cur) const
                    && (pos == 0 || par.getChar(pos - 1) != ' ')));
 }
 
+
+std::vector<docstring> Text::getFreeFonts() const
+{
+       vector<docstring> ffList;
+
+       FontStack::const_iterator cit = freeFonts.begin();
+       FontStack::const_iterator end = freeFonts.end();
+       for (; cit != end; ++cit)
+               // we do not use cit-> here because gcc 2.9x does not
+               // like it (JMarc)
+               ffList.push_back((*cit).first);
+
+       return ffList;
+}
+
 } // namespace lyx
index 4f705330f9d33301d24d2dd2a5422d80b0bbd240..4839ad378d268cbd787d4cb75a2de0d966a364cb 100644 (file)
@@ -42,7 +42,8 @@ int const num_math_fonts = sizeof(math_fonts) / sizeof(*math_fonts);
 
 namespace lyx {
 
-extern docstring const stateText(FontInfo const & f);
+extern docstring const stateText(FontInfo const & f,
+                                bool const terse = false);
 
 namespace frontend {
 
index ce1b2b7e7b1b371b96d869c9df1b5a86a2fbb498..ea2683b371ca6102b4566ae60579952112d3bae5 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "insets/InsetText.h"
 
+#include "support/convert.h"
 #include "support/debug.h"
 #include "support/gettext.h"
 #include "support/lstrings.h"
@@ -318,8 +319,9 @@ void DynamicMenuButton::initialize()
 
 bool DynamicMenuButton::isMenuType(string const & s)
 {
-       return s == "dynamic-custom-insets" ||
-              s == "dynamic-char-styles";
+       return s == "dynamic-custom-insets"
+               || s == "dynamic-char-styles"
+               || s == "dynamic-freefonts";
 }
 
 
@@ -336,28 +338,54 @@ void DynamicMenuButton::updateTriggered()
                setEnabled(false);
                setMinimumWidth(sizeHint().width());
                d->text_class_.reset();
-               d->inset_ = 0;
+               d->inset_ = nullptr;
                return;
        }
 
-       DocumentClassConstPtr text_class = 
-                       bv->buffer().params().documentClassPtr();
-       InsetText const * inset = &(bv->cursor().innerText()->inset());
-       // if the text class has changed, then we need to reload the menu
-       if (d->text_class_ != text_class) {
-               d->text_class_ = text_class;
-               // at the moment, we can just call loadFlexInsets, and it will
-               // handle both types. if there were more types of menus, then we 
-               // might need to have other options.
-               loadFlexInsets();
+       string const & menutype = tbitem_.name_;
+       if (menutype == "dynamic-custom-insets" || menutype == "dynamic-char-styles") {
+               DocumentClassConstPtr text_class =
+                               bv->buffer().params().documentClassPtr();
+               InsetText const * inset = &(bv->cursor().innerText()->inset());
+               // if the text class has changed, then we need to reload the menu
+               if (d->text_class_ != text_class) {
+                       d->text_class_ = text_class;
+                       // at the moment, we can just call loadFlexInsets, and it will
+                       // handle both types. if there were more types of menus, then we
+                       // might need to have other options.
+                       loadFlexInsets();
+               }
+               // remember where we are
+               d->inset_ = inset;
+               // note that enabling here might need to be more subtle if there
+               // were other kinds of menus.
+               setEnabled(!bv->buffer().isReadonly()
+                          && !m->isEmpty()
+                          && inset->insetAllowed(FLEX_CODE));
+       } else if (menutype == "dynamic-freefonts") {
+               m->clear();
+               vector<docstring> ffList = bv->cursor().innerText()->getFreeFonts();
+               unsigned int i = 0;
+               Action * default_act = nullptr;
+               for (auto const & f : ffList) {
+                       FuncRequest func(LFUN_TEXTSTYLE_APPLY, convert<docstring>(i),
+                                        FuncRequest::TOOLBAR);
+                       docstring const lb = char_type('&') + convert<docstring>(i)
+                               + from_ascii(". ") + f ;
+                       Action * act = new Action(func, QIcon(), toqstr(lb), toqstr(f), this);
+                       m->addAction(act);
+                       // The most recent one is the default
+                       if (i == 0)
+                               default_act = act;
+                       ++i;
+               }
+               if (default_act) {
+                       QToolButton::setDefaultAction(default_act);
+                       QToolButton::setIcon(getIcon(FuncRequest(LFUN_TEXTSTYLE_APPLY), false));
+               }
+               setPopupMode(QToolButton::DelayedPopup);
+               setEnabled(lyx::getStatus(FuncRequest(LFUN_TEXTSTYLE_APPLY)).enabled());
        }
-       // remember where we are
-       d->inset_ = inset;
-       // note that enabling here might need to be more subtle if there
-       // were other kinds of menus.
-       setEnabled(!bv->buffer().isReadonly() &&
-                                                !m->isEmpty() && 
-                                                inset->insetAllowed(FLEX_CODE));
 }
 
 
index c82134790b4f553eab832a8ea7c091bd53a9dc45..da09bbfbbff5f52ae456674a30cafde27aee6059 100644 (file)
@@ -86,6 +86,7 @@ protected Q_SLOTS:
 /// (stdtoolbars.inc, usually) and must be one of:
 ///            dynamic-custom-insets
 ///            dynamic-char-styles
+///            dynamic-freefonts
 /// To add a new one of these, you must add a routine, like 
 /// loadFlexInsets, that will populate the menu, and call it from
 /// updateTriggered. Make sure to add the new type to isMenuType().