commit cc4bfc7f04dc5a16347172f064f910ff3d26df9d
Author: Richard Heck <rgh...@lyx.org>
Date:   Fri Jun 24 17:47:30 2016 -0400

    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?
---
 lib/Makefile.am                              |    4 +
 lib/images/dynamic-char-styles.svgz          |  Bin 0 -> 1586 bytes
 lib/images/dynamic-custom-insets.svgz        |  Bin 0 -> 1586 bytes
 lib/images/oxygen/dynamic-char-styles.svgz   |  Bin 0 -> 30164 bytes
 lib/images/oxygen/dynamic-custom-insets.svgz |  Bin 0 -> 30164 bytes
 lib/ui/stdtoolbars.inc                       |    3 +
 src/frontends/qt4/GuiToolbar.cpp             |  179 +++++++++++++++++++++++---
 src/frontends/qt4/GuiToolbar.h               |   64 +++++++++-
 src/frontends/qt4/Toolbars.cpp               |   14 ++-
 src/frontends/qt4/Toolbars.h                 |    4 +-
 10 files changed, 241 insertions(+), 27 deletions(-)

diff --git a/lib/Makefile.am b/lib/Makefile.am
index f86b6de..2b3ea9a 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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 \
diff --git a/lib/images/dynamic-char-styles.svgz 
b/lib/images/dynamic-char-styles.svgz
new file mode 100644
index 0000000..715b5f3
Binary files /dev/null and b/lib/images/dynamic-char-styles.svgz differ
diff --git a/lib/images/dynamic-custom-insets.svgz 
b/lib/images/dynamic-custom-insets.svgz
new file mode 100644
index 0000000..715b5f3
Binary files /dev/null and b/lib/images/dynamic-custom-insets.svgz differ
diff --git a/lib/images/oxygen/dynamic-char-styles.svgz 
b/lib/images/oxygen/dynamic-char-styles.svgz
new file mode 100644
index 0000000..486a373
Binary files /dev/null and b/lib/images/oxygen/dynamic-char-styles.svgz differ
diff --git a/lib/images/oxygen/dynamic-custom-insets.svgz 
b/lib/images/oxygen/dynamic-custom-insets.svgz
new file mode 100644
index 0000000..486a373
Binary files /dev/null and b/lib/images/oxygen/dynamic-custom-insets.svgz differ
diff --git a/lib/ui/stdtoolbars.inc b/lib/ui/stdtoolbars.inc
index 3cabda3..54bea8a 100644
--- a/lib/ui/stdtoolbars.inc
+++ b/lib/ui/stdtoolbars.inc
@@ -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"
diff --git a/src/frontends/qt4/GuiToolbar.cpp b/src/frontends/qt4/GuiToolbar.cpp
index db96e0e..ce1b2b7 100644
--- a/src/frontends/qt4/GuiToolbar.cpp
+++ b/src/frontends/qt4/GuiToolbar.cpp
@@ -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));
diff --git a/src/frontends/qt4/GuiToolbar.h b/src/frontends/qt4/GuiToolbar.h
index badd599..c821347 100644
--- a/src/frontends/qt4/GuiToolbar.h
+++ b/src/frontends/qt4/GuiToolbar.h
@@ -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:
        ///
diff --git a/src/frontends/qt4/Toolbars.cpp b/src/frontends/qt4/Toolbars.cpp
index a2f8a0b..bf4617c 100644
--- a/src/frontends/qt4/Toolbars.cpp
+++ b/src/frontends/qt4/Toolbars.cpp
@@ -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();
diff --git a/src/frontends/qt4/Toolbars.h b/src/frontends/qt4/Toolbars.h
index a65d05e..a4acb41 100644
--- a/src/frontends/qt4/Toolbars.h
+++ b/src/frontends/qt4/Toolbars.h
@@ -44,7 +44,9 @@ public:
                /// a button that expands a menu but remembers the last choice
                STICKYPOPUPMENU,
                ///
-               ICONPALETTE
+               ICONPALETTE,
+               ///
+               DYNAMICMENU
        };
 
        ToolbarItem(Type type,

Reply via email to