I thought I'd have a go at enabling the external inset to have a renderer that can be chosen dynamically. As proof of concept, I thought I would define GraphicInset and ButtonInset, both these classes deriving from a common base class. The framework now exists to display the contents of the external file as text if that is what is desired.
Attached is the resulting patch and a screenshot of the inset in action. The patch isn't really ready to be applied, because André has "stolen" my favoured name ButtonInset, so I've had to call mine ButtonAsInset. Crap I know. However, this raises the real point of the exercise. Should our insets derive from InsetButton (mathed ButtonInset) or should they really contain a ButtonAsInset member variable to do the on-screen drawing for them. If we went for the latter option, then we would also simplify the code in InsetCollapsible which currently duplicates the InsetButton code. Thoughts? -- Angus
Index: src/insets/insetexternal.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insetexternal.C,v retrieving revision 1.79 diff -u -p -r1.79 insetexternal.C --- src/insets/insetexternal.C 11 Jun 2003 14:30:04 -0000 1.79 +++ src/insets/insetexternal.C 11 Jun 2003 17:09:56 -0000 @@ -82,19 +82,20 @@ InsetExternal::Params::~Params() InsetExternal::InsetExternal() - : renderer_(new GraphicInset) -{ - renderer_->connect(boost::bind(&InsetExternal::statusChanged, this)); -} + : renderer_(new ButtonAsInset(true)) +{} InsetExternal::InsetExternal(InsetExternal const & other) : Inset(other), boost::signals::trackable(), params_(other.params_), - renderer_(new GraphicInset(*other.renderer_)) + renderer_(other.renderer_->clone()) { - renderer_->connect(boost::bind(&InsetExternal::statusChanged, this)); + GraphicInset * ptr = dynamic_cast<GraphicInset *>(renderer_.get()); + if (ptr) { + ptr->connect(boost::bind(&InsetExternal::statusChanged, this)); + } } @@ -220,6 +221,7 @@ string const getScreenLabel(InsetExterna return doSubstitution(params, 0, ptr->guiName); } + } // namespace anon @@ -231,16 +233,34 @@ void InsetExternal::setParams(Params con params_.display = p.display; params_.lyxscale = p.lyxscale; - // A temporary set of params; whether the thing can be displayed - // within LyX depends on the availability of this template. - Params tmp = params_; - if (!getTemplatePtr(params_)) - tmp.display = grfx::NoDisplay; - - // Update the display using the new parameters. - if (params_.filename.empty() || !filepath.empty()) - renderer_->update(get_grfx_params(tmp, filepath)); - renderer_->setNoDisplayMessage(getScreenLabel(params_)); + // We display the inset as a button by default. + bool display_button = (!getTemplatePtr(params_) || + params_.filename.empty() || + filepath.empty() || + params_.display == grfx::NoDisplay); + + if (display_button) { + ButtonAsInset * button_ptr = + dynamic_cast<ButtonAsInset *>(renderer_.get()); + if (!button_ptr) { + button_ptr = new ButtonAsInset(true); + renderer_.reset(button_ptr); + } + + button_ptr->update(getScreenLabel(params_)); + + } else { + GraphicInset * graphic_ptr = + dynamic_cast<GraphicInset *>(renderer_.get()); + if (!graphic_ptr) { + graphic_ptr = new GraphicInset; + graphic_ptr->connect( + boost::bind(&InsetExternal::statusChanged, this)); + renderer_.reset(graphic_ptr); + } + + graphic_ptr->update(get_grfx_params(params_, filepath)); + } } Index: src/insets/insetexternal.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insetexternal.h,v retrieving revision 1.41 diff -u -p -r1.41 insetexternal.h --- src/insets/insetexternal.h 11 Jun 2003 14:30:04 -0000 1.41 +++ src/insets/insetexternal.h 11 Jun 2003 17:09:56 -0000 @@ -20,7 +20,7 @@ #include <boost/signals/trackable.hpp> -class GraphicInset; +class RenderInset; /// class InsetExternal : public Inset, public boost::signals::trackable { @@ -116,7 +116,7 @@ private: Params params_; /// The thing that actually draws the image on LyX's screen. - boost::scoped_ptr<GraphicInset> const renderer_; + boost::scoped_ptr<RenderInset> renderer_; }; Index: src/insets/graphicinset.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/graphicinset.C,v retrieving revision 1.5 diff -u -p -r1.5 graphicinset.C --- src/insets/graphicinset.C 11 Jun 2003 11:01:34 -0000 1.5 +++ src/insets/graphicinset.C 11 Jun 2003 17:09:56 -0000 @@ -26,19 +26,96 @@ #include "support/filetools.h" +RenderInset::RenderInset() +{} + + +RenderInset::RenderInset(RenderInset const &) +{ + // Cached variables are not copied +} + + +RenderInset::~RenderInset() +{} + + +BufferView * RenderInset::view() const +{ + return view_.lock().get(); +} + + +ButtonAsInset::ButtonAsInset(bool editable) + : editable_(editable) +{} + + +RenderInset * ButtonAsInset::clone() const +{ + return new ButtonAsInset(*this); +} + + +void ButtonAsInset::update(string const & text) +{ + text_ = text; +} + + +void ButtonAsInset::metrics(MetricsInfo & mi, Dimension & dim) const +{ + lyx::Assert(mi.base.bv); + + LyXFont font(LyXFont::ALL_SANE); + font.decSize(); + + if (editable_) + font_metrics::buttonText(text_, font, dim.wid, dim.asc, dim.des); + else + font_metrics::rectText(text_, font, dim.wid, dim.asc, dim.des); + + dim.wid += 4; +} + + +void ButtonAsInset::draw(PainterInfo & pi, int x, int y) const +{ + lyx::Assert(pi.base.bv); + view_ = pi.base.bv->owner()->view(); + + // Draw it as a box with the LaTeX text + LyXFont font(LyXFont::ALL_SANE); + font.setColor(LColor::command).decSize(); + + if (editable_) { + pi.pain.buttonText(x + 2, y, text_, font); + } else { + pi.pain.rectText(x + 2, y, text_, font, + LColor::commandbg, LColor::commandframe); + } +} + + GraphicInset::GraphicInset() : checksum_(0) {} GraphicInset::GraphicInset(GraphicInset const & other) - : loader_(other.loader_), + : RenderInset(other), + loader_(other.loader_), params_(other.params_), - nodisplay_message_(other.nodisplay_message_), checksum_(0) {} +RenderInset * GraphicInset::clone() const +{ + return new GraphicInset(*this); +} + + void GraphicInset::update(grfx::Params const & params) { params_ = params; @@ -60,24 +137,12 @@ bool GraphicInset::hasFileChanged() cons } -BufferView * GraphicInset::view() const -{ - return view_.lock().get(); -} - - boost::signals::connection GraphicInset::connect(slot_type const & slot) const { return loader_.connect(slot); } -void GraphicInset::setNoDisplayMessage(string const & str) -{ - nodisplay_message_ = str; -} - - string const GraphicInset::statusMessage() const { switch (loader_.status()) { @@ -108,33 +173,25 @@ string const GraphicInset::statusMessage } -GraphicInset::DisplayType GraphicInset::displayType() const +bool GraphicInset::readyToDisplay() const { - if (params_.display == grfx::NoDisplay && !nodisplay_message_.empty()) - return NODISPLAY_MESSAGE; - if (!loader_.image() || loader_.status() != grfx::Ready) - return STATUS_MESSAGE; - - return loader_.image()->isDrawable() ? IMAGE : STATUS_MESSAGE; + return false; + return loader_.image()->isDrawable(); } void GraphicInset::metrics(MetricsInfo & mi, Dimension & dim) const { - DisplayType type = displayType(); + bool image_ready = readyToDisplay(); - dim.asc = (type == IMAGE) ? loader_.image()->getHeight() : 50; + dim.asc = image_ready ? loader_.image()->getHeight() : 50; dim.des = 0; - switch (type) { - case IMAGE: + if (image_ready) { dim.wid = loader_.image()->getWidth() + 2 * Inset::TEXT_TO_INSET_OFFSET; - break; - - case STATUS_MESSAGE: - { + } else { int font_width = 0; LyXFont msgFont(mi.base.font); @@ -154,21 +211,6 @@ void GraphicInset::metrics(MetricsInfo & } dim.wid = std::max(50, font_width + 15); - break; - } - - case NODISPLAY_MESSAGE: - { - int font_width = 0; - - LyXFont msgFont(mi.base.font); - msgFont.setFamily(LyXFont::SANS_FAMILY); - msgFont.setSize(LyXFont::SIZE_FOOTNOTE); - font_width = font_metrics::width(nodisplay_message_, msgFont); - - dim.wid = std::max(50, font_width + 15); - break; - } } dim_ = dim; @@ -177,8 +219,8 @@ void GraphicInset::metrics(MetricsInfo & void GraphicInset::draw(PainterInfo & pi, int x, int y) const { - if (pi.base.bv) - view_ = pi.base.bv->owner()->view(); + lyx::Assert(pi.base.bv); + view_ = pi.base.bv->owner()->view(); #if 0 // Comment this out and see if anything goes wrong. @@ -215,19 +257,14 @@ void GraphicInset::draw(PainterInfo & pi // This will draw the graphics. If the graphics has not been loaded yet, // we draw just a rectangle. - switch (displayType()) { - case IMAGE: - { + if (readyToDisplay()) { pi.pain.image(x + Inset::TEXT_TO_INSET_OFFSET, y - dim_.asc, dim_.wid - 2 * Inset::TEXT_TO_INSET_OFFSET, dim_.asc + dim_.des, *loader_.image()); - break; - } - case STATUS_MESSAGE: - { + } else { pi.pain.rectangle(x + Inset::TEXT_TO_INSET_OFFSET, y - dim_.asc, dim_.wid - 2 * Inset::TEXT_TO_INSET_OFFSET, @@ -252,23 +289,5 @@ void GraphicInset::draw(PainterInfo & pi pi.pain.text(x + Inset::TEXT_TO_INSET_OFFSET + 6, y - 4, msg, msgFont); } - break; - } - - case NODISPLAY_MESSAGE: - { - pi.pain.rectangle(x + Inset::TEXT_TO_INSET_OFFSET, - y - dim_.asc, - dim_.wid - 2 * Inset::TEXT_TO_INSET_OFFSET, - dim_.asc + dim_.des); - - LyXFont msgFont = pi.base.font; - msgFont.setFamily(LyXFont::SANS_FAMILY); - msgFont.setSize(LyXFont::SIZE_FOOTNOTE); - pi.pain.text(x + Inset::TEXT_TO_INSET_OFFSET + 6, - y - font_metrics::maxAscent(msgFont) - 4, - nodisplay_message_, msgFont); - break; - } } } Index: src/insets/graphicinset.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/graphicinset.h,v retrieving revision 1.5 diff -u -p -r1.5 graphicinset.h --- src/insets/graphicinset.h 11 Jun 2003 11:01:34 -0000 1.5 +++ src/insets/graphicinset.h 11 Jun 2003 17:09:56 -0000 @@ -27,38 +27,80 @@ class MetricsInfo; class PainterInfo; -class GraphicInset +class RenderInset +{ +public: + virtual ~RenderInset(); + + virtual RenderInset * clone() const = 0; + + /// compute the size of the object returned in dim + virtual void metrics(MetricsInfo & mi, Dimension & dim) const = 0; + /// draw inset and update (xo, yo)-cache + virtual void draw(PainterInfo & pi, int x, int y) const = 0; + + /// An accessor function to the cached store. + BufferView * view() const; + +protected: + RenderInset(); + RenderInset(RenderInset const &); + + /// These are cached variables (are not copied). + mutable boost::weak_ptr<BufferView> view_; + mutable Dimension dim_; +}; + + +class ButtonAsInset : public RenderInset +{ +public: + ButtonAsInset(bool editable); + + virtual RenderInset * clone() const; + + /// This should provide the text for the button + void update(string const &); + + /// compute the size of the object returned in dim + virtual void metrics(MetricsInfo & mi, Dimension & dim) const; + /// draw inset and update (xo, yo)-cache + virtual void draw(PainterInfo & pi, int x, int y) const; + +private: + /// Not implemented. + ButtonAsInset & operator=(ButtonAsInset const &); + + /// The stored data. + string text_; + bool editable_; +}; + + +class GraphicInset : public RenderInset { public: GraphicInset(); GraphicInset(GraphicInset const &); - /** Set the message that the inset will show when the - * display of the graphic is deactivated. - * The default is nothing, meaning that the inset will - * show a message descibing the state of the image - * loading process. - */ - void setNoDisplayMessage(string const & msg); - + virtual RenderInset * clone() const; + /// Refresh the info about which file to display and how to display it. void update(grfx::Params const & params); /// compute the size of the object returned in dim - void metrics(MetricsInfo & mi, Dimension & dim) const; + virtual void metrics(MetricsInfo & mi, Dimension & dim) const; /// draw inset and update (xo, yo)-cache - void draw(PainterInfo & pi, int x, int y) const; + virtual void draw(PainterInfo & pi, int x, int y) const; /// Is the stored checksum different to that of the graphics loader? bool hasFileChanged() const; - /// An accessor function to the cached store. - BufferView * view() const; /** Connect and you'll be informed when the loading status of the image * changes. */ typedef boost::signal0<void>::slot_type slot_type; - boost::signals::connection connect(slot_type const &) const; + virtual boost::signals::connection connect(slot_type const &) const; private: /// Not implemented. @@ -67,24 +109,15 @@ private: /// The message to display instead of the graphic itself. string const statusMessage() const; - enum DisplayType { - IMAGE, - STATUS_MESSAGE, - NODISPLAY_MESSAGE - }; - /// Is the image ready to draw, or should we display a message instead? - DisplayType displayType() const; + bool readyToDisplay() const; /// The stored data. grfx::Loader loader_; grfx::Params params_; - string nodisplay_message_; - /// These are all cached variables. + /// Cached variable (not copied). mutable unsigned long checksum_; - mutable boost::weak_ptr<BufferView> view_; - mutable Dimension dim_; };
<<attachment: lyxscreen.png>>