Add toolbar menus for custom insets and character styles.

I'm open to putting this elsewhere on the toolbar, or even on a
different toolbar. Also, we need decent icons. These ones are not
intended seriously but were just borrowed for testing purposes.
Anyone have good ideas about icons?
This commit is contained in:
Richard Heck 2016-06-24 17:47:30 -04:00 committed by Richard Kimberly Heck
parent e91245362f
commit cc4bfc7f04
10 changed files with 241 additions and 27 deletions

View File

@ -469,6 +469,8 @@ dist_images_DATA1X = \
images/dialog-toggle_findreplaceadv.svgz \
images/dialog-toggle_toc.svgz \
images/down.svgz \
images/dynamic-char-styles.svgz \
images/dynamic-custom-insets.svgz \
images/editclear.svgz \
images/emblem-readonly.svgz \
images/emblem-shellescape.svgz \
@ -1746,6 +1748,8 @@ dist_imagesoxygen_DATA1X = \
images/oxygen/dialog-show_vclog.svgz \
images/oxygen/dialog-toggle_findreplaceadv.svgz \
images/oxygen/dialog-toggle_toc.svgz \
images/oxygen/dynamic-char-styles.svgz \
images/oxygen/dynamic-custom-insets.svgz \
images/oxygen/down.svgz \
images/oxygen/editclear.svgz \
images/oxygen/ert-insert.svgz \

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -96,6 +96,9 @@ ToolbarSet
Item "Toggle math toolbar" "toolbar-toggle math"
Item "Toggle table toolbar" "toolbar-toggle table"
Item "Toggle review toolbar" "toolbar-toggle review"
Separator
DynamicMenu "dynamic-custom-insets" "Custom Insets"
DynamicMenu "dynamic-char-styles" "Character Styles"
End
Toolbar "view/update" "View/Update"

View File

@ -18,21 +18,28 @@
#include "GuiToolbar.h"
#include "Action.h"
#include "Buffer.h"
#include "BufferParams.h"
#include "BufferView.h"
#include "Cursor.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "GuiApplication.h"
#include "GuiCommandBuffer.h"
#include "GuiView.h"
#include "IconPalette.h"
#include "InsertTableWidget.h"
#include "LayoutBox.h"
#include "qt_helpers.h"
#include "Toolbars.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "KeyMap.h"
#include "LayoutBox.h"
#include "LyX.h"
#include "LyXRC.h"
#include "qt_helpers.h"
#include "Session.h"
#include "Text.h"
#include "TextClass.h"
#include "Toolbars.h"
#include "insets/InsetText.h"
#include "support/debug.h"
#include "support/gettext.h"
@ -181,7 +188,7 @@ public:
} // namespace
MenuButton::MenuButton(GuiToolbar * bar, ToolbarItem const & item, bool const sticky)
MenuButtonBase::MenuButtonBase(GuiToolbar * bar, ToolbarItem const & item)
: QToolButton(bar), bar_(bar), tbitem_(item)
{
setPopupMode(QToolButton::InstantPopup);
@ -201,6 +208,20 @@ MenuButton::MenuButton(GuiToolbar * bar, ToolbarItem const & item, bool const st
break;
}
}
}
void MenuButtonBase::actionTriggered(QAction * action)
{
QToolButton::setDefaultAction(action);
setPopupMode(QToolButton::DelayedPopup);
}
StaticMenuButton::StaticMenuButton(
GuiToolbar * bar, ToolbarItem const & item, bool const sticky)
: MenuButtonBase(bar, item)
{
if (sticky)
connect(this, SIGNAL(triggered(QAction *)),
this, SLOT(actionTriggered(QAction *)));
@ -210,7 +231,7 @@ MenuButton::MenuButton(GuiToolbar * bar, ToolbarItem const & item, bool const st
}
void MenuButton::initialize()
void StaticMenuButton::initialize()
{
QString const label = qt_(to_ascii(tbitem_.label_));
ButtonMenu * m = new ButtonMenu(label, this);
@ -232,14 +253,7 @@ void MenuButton::initialize()
}
void MenuButton::actionTriggered(QAction * action)
{
QToolButton::setDefaultAction(action);
setPopupMode(QToolButton::DelayedPopup);
}
void MenuButton::updateTriggered()
void StaticMenuButton::updateTriggered()
{
if (!menu())
return;
@ -261,6 +275,126 @@ void MenuButton::updateTriggered()
}
class DynamicMenuButton::Private
{
/// noncopyable
Private(Private const &);
void operator=(Private const &);
public:
Private() : inset_(0) {}
///
DocumentClassConstPtr text_class_;
///
InsetText const * inset_;
};
DynamicMenuButton::DynamicMenuButton(GuiToolbar * bar, ToolbarItem const & item)
: MenuButtonBase(bar, item), d(new Private())
{
initialize();
}
DynamicMenuButton::~DynamicMenuButton()
{
delete d;
}
void DynamicMenuButton::initialize()
{
QString const label = qt_(to_ascii(tbitem_.label_));
ButtonMenu * m = new ButtonMenu(label, this);
m->setWindowTitle(label);
m->setTearOffEnabled(true);
connect(bar_, SIGNAL(updated()), m, SLOT(updateParent()));
connect(bar_, SIGNAL(updated()), this, SLOT(updateTriggered()));
connect(bar_, SIGNAL(iconSizeChanged(QSize)),
this, SLOT(setIconSize(QSize)));
setMenu(m);
}
bool DynamicMenuButton::isMenuType(string const & s)
{
return s == "dynamic-custom-insets" ||
s == "dynamic-char-styles";
}
void DynamicMenuButton::updateTriggered()
{
QMenu * m = menu();
// the menu should exist by this point
// if not, we can at least avoid crashing in release mode
LASSERT(m, return);
GuiView const & owner = bar_->owner();
BufferView const * bv = owner.currentBufferView();
if (!bv) {
m->clear();
setEnabled(false);
setMinimumWidth(sizeHint().width());
d->text_class_.reset();
d->inset_ = 0;
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();
}
// 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));
}
void DynamicMenuButton::loadFlexInsets()
{
QMenu * m = menu();
m->clear();
string const & menutype = tbitem_.name_;
InsetLayout::InsetLyXType ftype;
if (menutype == "dynamic-custom-insets")
ftype = InsetLayout::CUSTOM;
else if (menutype == "dynamic-char-styles")
ftype = InsetLayout::CHARSTYLE;
else {
// this should have been taken care of earlier
LASSERT(false, return);
}
TextClass::InsetLayouts const & inset_layouts =
d->text_class_->insetLayouts();
for (auto const & iit : inset_layouts) {
InsetLayout const & il = iit.second;
if (il.lyxtype() != ftype)
continue;
docstring const name = iit.first;
QString const loc_item = toqstr(translateIfPossible(
prefixIs(name, from_ascii("Flex:")) ?
name.substr(5) : name));
FuncRequest func(LFUN_FLEX_INSERT,
from_ascii("\"") + name + from_ascii("\""), FuncRequest::TOOLBAR);
Action * act =
new Action(func, getIcon(func, false), loc_item, loc_item, this);
m->addAction(act);
}
}
void GuiToolbar::add(ToolbarItem const & item)
{
switch (item.type_) {
@ -299,15 +433,22 @@ void GuiToolbar::add(ToolbarItem const & item)
case ToolbarItem::ICONPALETTE:
addWidget(new PaletteButton(this, item));
break;
case ToolbarItem::POPUPMENU: {
addWidget(new MenuButton(this, item, false));
addWidget(new StaticMenuButton(this, item, false));
break;
}
case ToolbarItem::STICKYPOPUPMENU: {
addWidget(new MenuButton(this, item, true));
addWidget(new StaticMenuButton(this, item, true));
break;
}
case ToolbarItem::DYNAMICMENU: {
// we only handle certain things
if (DynamicMenuButton::isMenuType(item.name_))
addWidget(new DynamicMenuButton(this, item));
else
LYXERR0("Unknown dynamic menu type: " << item.name_);
break;
}
case ToolbarItem::COMMAND: {
if (!getStatus(*item.func_).unknown())
addAction(addItem(item));

View File

@ -20,6 +20,8 @@
#include <QToolBar>
#include <QToolButton>
#include "support/strfwd.h"
class QSettings;
namespace lyx {
@ -38,30 +40,78 @@ class LayoutBox;
class ToolbarInfo;
class ToolbarItem;
class MenuButton : public QToolButton
class MenuButtonBase : public QToolButton
{
Q_OBJECT
public:
///
MenuButton(GuiToolbar * bar, ToolbarItem const & item,
bool const sticky = false);
MenuButtonBase(GuiToolbar * bar, ToolbarItem const & item);
private:
protected:
///
void initialize();
virtual void initialize() = 0;
///
GuiToolbar * bar_;
///
ToolbarItem const & tbitem_;
private Q_SLOTS:
protected Q_SLOTS:
///
void actionTriggered(QAction * action);
///
virtual void updateTriggered() = 0;
};
class StaticMenuButton : public MenuButtonBase
{
Q_OBJECT
public:
///
StaticMenuButton(GuiToolbar * bar, ToolbarItem const & item,
bool const sticky = false);
protected:
///
void initialize();
protected Q_SLOTS:
///
void updateTriggered();
};
/// A menu which can be populated on the fly.
/// The 'type' of menu must be given in the toolbar file
/// (stdtoolbars.inc, usually) and must be one of:
/// dynamic-custom-insets
/// dynamic-char-styles
/// 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().
class DynamicMenuButton : public MenuButtonBase
{
Q_OBJECT
public:
///
DynamicMenuButton(GuiToolbar * bar, ToolbarItem const & item);
///
~DynamicMenuButton();
///
static bool isMenuType(std::string const & s);
protected:
///
void initialize();
///
void loadFlexInsets();
/// pimpl so we don't have to include big files
class Private;
Private * d;
protected Q_SLOTS:
///
void updateTriggered();
};
class GuiToolbar : public QToolBar
{
@ -107,6 +157,8 @@ public:
///
Action * addItem(ToolbarItem const & item);
///
GuiView const & owner() { return owner_; }
Q_SIGNALS:
///

View File

@ -74,10 +74,12 @@ ToolbarInfo & ToolbarInfo::read(Lexer & lex)
TO_EXPORTFORMATS,
TO_IMPORTFORMATS,
TO_UPDATEFORMATS,
TO_VIEWFORMATS
TO_VIEWFORMATS,
TO_DYNAMICMENU
};
struct LexerKeyword toolTags[] = {
{ "dynamicmenu", TO_DYNAMICMENU},
{ "end", TO_ENDTOOLBAR },
{ "exportformats", TO_EXPORTFORMATS },
{ "iconpalette", TO_ICONPALETTE },
@ -155,6 +157,16 @@ ToolbarInfo & ToolbarInfo::read(Lexer & lex)
}
break;
case TO_DYNAMICMENU: {
if (lex.next(true)) {
string const name = lex.getString();
lex.next(true);
docstring const label = lex.getDocString();
add(ToolbarItem(ToolbarItem::DYNAMICMENU, name, label));
}
break;
}
case TO_STICKYPOPUPMENU:
if (lex.next(true)) {
string const pname = lex.getString();

View File

@ -44,7 +44,9 @@ public:
/// a button that expands a menu but remembers the last choice
STICKYPOPUPMENU,
///
ICONPALETTE
ICONPALETTE,
///
DYNAMICMENU
};
ToolbarItem(Type type,