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 \
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 \
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 \
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"
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
}
-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)
}
-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")
/// 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;
/*!
* \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
///
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.
#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"
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,
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.
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;
}
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:
&& (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
namespace lyx {
-extern docstring const stateText(FontInfo const & f);
+extern docstring const stateText(FontInfo const & f,
+ bool const terse = false);
namespace frontend {
#include "insets/InsetText.h"
+#include "support/convert.h"
#include "support/debug.h"
#include "support/gettext.h"
#include "support/lstrings.h"
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";
}
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));
}
/// (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().