Andre Poenitz wrote:

> On Tue, Oct 21, 2003 at 11:41:41AM +0100, Angus Leeming wrote:
>> > What problem are you trying to solve that's not solvable by
>> > locally factoring out some common code from metrics() and draw()
>> > in a few fat insets?
>> 
>> Have I answered this question with the above?
> 
> Sort of.
> 
>> I _really_ would like the ability to mark-up text handled by the
>> frontends and think that a fully-fledged widget embedding one of
>> our Painters would be excessive in many instances...
> 
> Think to the end: This amounts to implementing a "stream language"
> which is capable to carry all "interesting" information. Not just
> font stuff, but a \hat accent and maybe a \sqrt drawing.
> 
> So this languange is more or less as powerful as the .lyx file
> format.
> 
> The core would encode data in this language and the frontends would
> "interpret" them. So the relation between frontend and
> streamlanguage is about the same as the between web browsers and
> HTML.
> 
> It might be an interesting idea, but in my opinion any step in this
> direction is a complete waste of resources of developers and users.
> Neither your nor we will finish creating the equivalent of two web
> browsers and the whole encoding/decoding idea smells like bloat.
> 
> If you have the feeling that the current drawing primitives by the
> frontends are not sufficient, try to point to a real problem. Maybe
> this could be overcome by a new "primitive" operation.
> 
> I really don't see a point in encoding font changes in a string to
> be drawn. The mechanism is the same for all frontends, so this work
> could as well be done in the core once.

FWIW, I agree with you ;-)

Anyway, in order to reach that opinion for myself, I tried to code it 
up. See attached.

int main() 
{
        font::MetricsStream fs;
        fs << font::setFamily(font::SERIF) << "angus"
           << font::setFamily(font::SANS_SERIF) << " leeming";

        int const width = font::getWidth(fs);
        std::cout << "Width = " << width << std::endl;

        xmlOutput(std::cout, fs);
        std::cout << std::endl;
        return 0;
}

Output:

Width = 13
<serif>angus</serif><sans_serif> leeming</sans_serif>

So, it could clearly be made to work.

-- 
Angus
#include <ostream>
#include <sstream>
#include <list>
#include <string>
#include <utility>

namespace font {

enum Family {
	SERIF,
	SANS_SERIF,
	TYPEWRITER
};


class setFamily;


class MetricsStream : public std::ostream {
public:
	std::ostringstream buffer;

	typedef std::string::size_type pos_type;
	typedef std::pair<pos_type, font::Family> FamilyPair;
	typedef std::list<FamilyPair> FamilyStack;

	FamilyStack family_stack_;
};


MetricsStream & operator<<(MetricsStream &, char const *);
MetricsStream & operator<<(MetricsStream &, std::string const &);
MetricsStream & operator<<(MetricsStream &, setFamily const &);


class setFamily {
public:
        explicit setFamily(Family family) : family_(family) {}
        friend MetricsStream & operator<<(MetricsStream &, setFamily const &);
private:
        Family family_;
};


int getWidth(MetricsStream const & os);

} // namespace font


// IMPLEMENTATION
namespace font {

MetricsStream & operator<<(MetricsStream & os, std::string const & text)
{
	os.buffer << text;
	return os;
}


MetricsStream & operator<<(MetricsStream & os, char const * text)
{
	if (text)
		os.buffer << text;
	return os;
}


MetricsStream & operator<<(MetricsStream & os, setFamily const & sf)
{
	MetricsStream::pos_type const pos = os.buffer.str().size();
	os.family_stack_.push_back(std::make_pair(pos, sf.family_));
	return os;
}


namespace {

MetricsStream::FamilyPair const nextFontChange(std::string::size_type cur,
					       MetricsStream const & os)
{
	typedef MetricsStream::FamilyStack::const_iterator iterator;
	iterator it  = os.family_stack_.begin();
	iterator end = os.family_stack_.end();
	for (; it != end; ++it) {
		if (it->first > cur)
			return *it;
	}
	return std::make_pair(std::string::npos, Family(-1));
}

void outputFamily(std::ostream & os,
		  char const * prefix,
		  Family family,
		  char const * postfix)
{
    os << prefix;
    switch (family) {
    case SERIF:
	os << "serif";
	break;
    case SANS_SERIF:
	os << "sans_serif";
	break;
    case TYPEWRITER:
	os << "typewriter";
	break;
    }
    os << postfix;
}

} // namespace anon

int getWidth(MetricsStream const & os)
{
	int width = 0;
	std::string const buffer = os.buffer.str();
	if (buffer.empty())
		return width;

	std::string::size_type pos = 0;
	while (pos != std::string::npos) {
		MetricsStream::FamilyPair const next_font =
			nextFontChange(pos, os);
		std::string::size_type const next = next_font.first;
		// The real thing would apply the font to this substring.
		width += buffer.substr(pos, next).size();
		pos = next;
	}
	return width;
}

void xmlOutput(std::ostream & os, MetricsStream const & ms)
{
 	std::string const buffer = ms.buffer.str();
	if (buffer.empty())
		return;

	std::string::size_type pos = 0;
	font::Family family = font::SERIF;

	while (pos != std::string::npos) {
		MetricsStream::FamilyPair const next_font =
			nextFontChange(pos, ms);
		std::string::size_type const next = next_font.first;
		std::string const substr = buffer.substr(pos, next);
		if (substr.empty())
			continue;

		outputFamily(os, "<", family, ">");
		os << substr;
		outputFamily(os, "</", family, ">");

		pos = next;
		family = next_font.second;
	}
}


} // namespace font


// MAIN
#include <iostream>

int main() 
{
	font::MetricsStream fs;
	fs << font::setFamily(font::SERIF) << "angus"
	   << font::setFamily(font::SANS_SERIF) << " leeming";

	int const width = font::getWidth(fs);
	std::cout << "Width = " << width << std::endl;

	xmlOutput(std::cout, fs);
	std::cout << std::endl;
	return 0;
}

Reply via email to