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>>

Reply via email to