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