implement text overlay support

This commit is contained in:
ZappoMan 2014-02-15 21:13:44 -08:00
parent 0a9f9a7c7a
commit ef11865d24
12 changed files with 382 additions and 122 deletions

View file

@ -44,6 +44,19 @@ for (s = 0; s < numberOfSwatches; s++) {
}); });
} }
var text = Overlays.addOverlay("text", {
x: 200,
y: 100,
width: 150,
height: 50,
backgroundColor: { red: 0, green: 0, blue: 0},
textColor: { red: 255, green: 0, blue: 0},
topMargin: 4,
leftMargin: 4,
alpha: 0.7,
text: "Here is some text.\nAnd a second line."
});
var toolA = Overlays.addOverlay("image", { var toolA = Overlays.addOverlay("image", {
x: 100, x: 100,
y: 100, y: 100,
@ -97,6 +110,7 @@ function scriptEnding() {
} }
Overlays.deleteOverlay(thumb); Overlays.deleteOverlay(thumb);
Overlays.deleteOverlay(slider); Overlays.deleteOverlay(slider);
Overlays.deleteOverlay(text);
} }
Script.scriptEnding.connect(scriptEnding); Script.scriptEnding.connect(scriptEnding);
@ -132,10 +146,14 @@ function mouseMoveEvent(event) {
} }
} }
function mousePressEvent(event) { function mousePressEvent(event) {
var clickedText = false;
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
if (clickedOverlay == thumb) { if (clickedOverlay == thumb) {
movingSlider = true; movingSlider = true;
thumbClickOffsetX = event.x - thumbX; thumbClickOffsetX = event.x - thumbX;
} else if (clickedOverlay == text) {
Overlays.editOverlay(text, { text: "you clicked here:\n " + event.x + "," + event.y } );
clickedText = true;
} else { } else {
for (s = 0; s < numberOfSwatches; s++) { for (s = 0; s < numberOfSwatches; s++) {
if (clickedOverlay == swatches[s]) { if (clickedOverlay == swatches[s]) {
@ -145,6 +163,9 @@ function mousePressEvent(event) {
} }
} }
} }
if (!clickedText) {
Overlays.editOverlay(text, { text: "you didn't click here" } );
}
} }
function mouseReleaseEvent(event) { function mouseReleaseEvent(event) {

View file

@ -19,15 +19,6 @@
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include <QSettings> #include <QSettings>
// the standard sans serif font family
#define SANS_FONT_FAMILY "Helvetica"
// the standard mono font family
#define MONO_FONT_FAMILY "Courier"
// the Inconsolata font family
#define INCONSOLATA_FONT_FAMILY "Inconsolata"
void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * fwd, glm::vec3 * left, glm::vec3 * up); void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * fwd, glm::vec3 * left, glm::vec3 * up);
float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos); float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos);

View file

@ -14,23 +14,13 @@
#include <SharedUtil.h> #include <SharedUtil.h>
ImageOverlay::ImageOverlay() : ImageOverlay::ImageOverlay() :
_parent(NULL),
_textureID(0), _textureID(0),
_alpha(DEFAULT_ALPHA),
_backgroundColor(DEFAULT_BACKGROUND_COLOR),
_visible(true),
_renderImage(false), _renderImage(false),
_textureBound(false), _textureBound(false),
_wantClipFromImage(false) _wantClipFromImage(false)
{ {
} }
void ImageOverlay::init(QGLWidget* parent) {
qDebug() << "ImageOverlay::init() parent=" << parent;
_parent = parent;
}
ImageOverlay::~ImageOverlay() { ImageOverlay::~ImageOverlay() {
if (_parent && _textureID) { if (_parent && _textureID) {
// do we need to call this? // do we need to call this?
@ -114,44 +104,9 @@ void ImageOverlay::render() {
} }
} }
// TODO: handle only setting the included values...
void ImageOverlay::setProperties(const QScriptValue& properties) { void ImageOverlay::setProperties(const QScriptValue& properties) {
//qDebug() << "ImageOverlay::setProperties()... properties=" << &properties; Overlay::setProperties(properties);
QScriptValue bounds = properties.property("bounds");
if (bounds.isValid()) {
QRect boundsRect;
boundsRect.setX(bounds.property("x").toVariant().toInt());
boundsRect.setY(bounds.property("y").toVariant().toInt());
boundsRect.setWidth(bounds.property("width").toVariant().toInt());
boundsRect.setHeight(bounds.property("height").toVariant().toInt());
setBounds(boundsRect);
} else {
QRect oldBounds = getBounds();
QRect newBounds = oldBounds;
if (properties.property("x").isValid()) {
newBounds.setX(properties.property("x").toVariant().toInt());
} else {
newBounds.setX(oldBounds.x());
}
if (properties.property("y").isValid()) {
newBounds.setY(properties.property("y").toVariant().toInt());
} else {
newBounds.setY(oldBounds.y());
}
if (properties.property("width").isValid()) {
newBounds.setWidth(properties.property("width").toVariant().toInt());
} else {
newBounds.setWidth(oldBounds.width());
}
if (properties.property("height").isValid()) {
newBounds.setHeight(properties.property("height").toVariant().toInt());
} else {
newBounds.setHeight(oldBounds.height());
}
setBounds(newBounds);
//qDebug() << "set bounds to " << getBounds();
}
QScriptValue subImageBounds = properties.property("subImage"); QScriptValue subImageBounds = properties.property("subImage");
if (subImageBounds.isValid()) { if (subImageBounds.isValid()) {
QRect oldSubImageRect = _fromImage; QRect oldSubImageRect = _fromImage;
@ -183,26 +138,6 @@ void ImageOverlay::setProperties(const QScriptValue& properties) {
if (imageURL.isValid()) { if (imageURL.isValid()) {
setImageURL(imageURL.toVariant().toString()); setImageURL(imageURL.toVariant().toString());
} }
QScriptValue color = properties.property("backgroundColor");
if (color.isValid()) {
QScriptValue red = color.property("red");
QScriptValue green = color.property("green");
QScriptValue blue = color.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_backgroundColor.red = red.toVariant().toInt();
_backgroundColor.green = green.toVariant().toInt();
_backgroundColor.blue = blue.toVariant().toInt();
}
}
if (properties.property("alpha").isValid()) {
setAlpha(properties.property("alpha").toVariant().toFloat());
}
if (properties.property("visible").isValid()) {
setVisible(properties.property("visible").toVariant().toBool());
}
} }

View file

@ -22,43 +22,24 @@
#include <SharedUtil.h> #include <SharedUtil.h>
const xColor DEFAULT_BACKGROUND_COLOR = { 255, 255, 255 }; #include "Overlay.h"
const float DEFAULT_ALPHA = 0.7f;
class ImageOverlay : QObject { class ImageOverlay : public Overlay {
Q_OBJECT Q_OBJECT
public: public:
ImageOverlay(); ImageOverlay();
~ImageOverlay(); ~ImageOverlay();
void init(QGLWidget* parent); virtual void render();
void render();
//public slots:
// getters // getters
bool getVisible() const { return _visible; }
int getX() const { return _bounds.x(); }
int getY() const { return _bounds.y(); }
int getWidth() const { return _bounds.width(); }
int getHeight() const { return _bounds.height(); }
const QRect& getBounds() const { return _bounds; }
const QRect& getClipFromSource() const { return _fromImage; } const QRect& getClipFromSource() const { return _fromImage; }
const xColor& getBackgroundColor() const { return _backgroundColor; }
float getAlpha() const { return _alpha; }
const QUrl& getImageURL() const { return _imageURL; } const QUrl& getImageURL() const { return _imageURL; }
// setters // setters
void setVisible(bool visible) { _visible = visible; }
void setX(int x) { _bounds.setX(x); }
void setY(int y) { _bounds.setY(y); }
void setWidth(int width) { _bounds.setWidth(width); }
void setHeight(int height) { _bounds.setHeight(height); }
void setBounds(const QRect& bounds) { _bounds = bounds; }
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; } void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; }
void setBackgroundColor(const xColor& color) { _backgroundColor = color; }
void setAlpha(float alpha) { _alpha = alpha; }
void setImageURL(const QUrl& url); void setImageURL(const QUrl& url);
void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
private slots: private slots:
void replyFinished(QNetworkReply* reply); // we actually want to hide this... void replyFinished(QNetworkReply* reply); // we actually want to hide this...
@ -66,14 +47,9 @@ private slots:
private: private:
QUrl _imageURL; QUrl _imageURL;
QGLWidget* _parent;
QImage _textureImage; QImage _textureImage;
GLuint _textureID; GLuint _textureID;
QRect _bounds; // where on the screen to draw
QRect _fromImage; // where from in the image to sample QRect _fromImage; // where from in the image to sample
float _alpha;
xColor _backgroundColor;
bool _visible; // should the overlay be drawn at all
bool _renderImage; // is there an image associated with this overlay, or is it just a colored rectangle bool _renderImage; // is there an image associated with this overlay, or is it just a colored rectangle
bool _textureBound; // has the texture been bound bool _textureBound; // has the texture been bound
bool _wantClipFromImage; bool _wantClipFromImage;

View file

@ -0,0 +1,88 @@
//
// Overlay.cpp
// interface
//
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#include "Overlay.h"
#include <QSvgRenderer>
#include <QPainter>
#include <QGLWidget>
#include <SharedUtil.h>
Overlay::Overlay() :
_parent(NULL),
_alpha(DEFAULT_ALPHA),
_backgroundColor(DEFAULT_BACKGROUND_COLOR),
_visible(true)
{
}
void Overlay::init(QGLWidget* parent) {
_parent = parent;
}
Overlay::~Overlay() {
}
void Overlay::setProperties(const QScriptValue& properties) {
QScriptValue bounds = properties.property("bounds");
if (bounds.isValid()) {
QRect boundsRect;
boundsRect.setX(bounds.property("x").toVariant().toInt());
boundsRect.setY(bounds.property("y").toVariant().toInt());
boundsRect.setWidth(bounds.property("width").toVariant().toInt());
boundsRect.setHeight(bounds.property("height").toVariant().toInt());
setBounds(boundsRect);
} else {
QRect oldBounds = getBounds();
QRect newBounds = oldBounds;
if (properties.property("x").isValid()) {
newBounds.setX(properties.property("x").toVariant().toInt());
} else {
newBounds.setX(oldBounds.x());
}
if (properties.property("y").isValid()) {
newBounds.setY(properties.property("y").toVariant().toInt());
} else {
newBounds.setY(oldBounds.y());
}
if (properties.property("width").isValid()) {
newBounds.setWidth(properties.property("width").toVariant().toInt());
} else {
newBounds.setWidth(oldBounds.width());
}
if (properties.property("height").isValid()) {
newBounds.setHeight(properties.property("height").toVariant().toInt());
} else {
newBounds.setHeight(oldBounds.height());
}
setBounds(newBounds);
//qDebug() << "set bounds to " << getBounds();
}
QScriptValue color = properties.property("backgroundColor");
if (color.isValid()) {
QScriptValue red = color.property("red");
QScriptValue green = color.property("green");
QScriptValue blue = color.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_backgroundColor.red = red.toVariant().toInt();
_backgroundColor.green = green.toVariant().toInt();
_backgroundColor.blue = blue.toVariant().toInt();
}
}
if (properties.property("alpha").isValid()) {
setAlpha(properties.property("alpha").toVariant().toFloat());
}
if (properties.property("visible").isValid()) {
setVisible(properties.property("visible").toVariant().toBool());
}
}

View file

@ -0,0 +1,64 @@
//
// Overlay.h
// interface
//
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__Overlay__
#define __interface__Overlay__
// include this before QGLWidget, which includes an earlier version of OpenGL
#include "InterfaceConfig.h"
#include <QGLWidget>
#include <QRect>
#include <QScriptValue>
#include <QString>
#include <SharedUtil.h> // for xColor
const xColor DEFAULT_BACKGROUND_COLOR = { 255, 255, 255 };
const float DEFAULT_ALPHA = 0.7f;
class Overlay : public QObject {
Q_OBJECT
public:
Overlay();
~Overlay();
void init(QGLWidget* parent);
virtual void render() = 0;
// getters
bool getVisible() const { return _visible; }
int getX() const { return _bounds.x(); }
int getY() const { return _bounds.y(); }
int getWidth() const { return _bounds.width(); }
int getHeight() const { return _bounds.height(); }
const QRect& getBounds() const { return _bounds; }
const xColor& getBackgroundColor() const { return _backgroundColor; }
float getAlpha() const { return _alpha; }
// setters
void setVisible(bool visible) { _visible = visible; }
void setX(int x) { _bounds.setX(x); }
void setY(int y) { _bounds.setY(y); }
void setWidth(int width) { _bounds.setWidth(width); }
void setHeight(int height) { _bounds.setHeight(height); }
void setBounds(const QRect& bounds) { _bounds = bounds; }
void setBackgroundColor(const xColor& color) { _backgroundColor = color; }
void setAlpha(float alpha) { _alpha = alpha; }
virtual void setProperties(const QScriptValue& properties);
protected:
QGLWidget* _parent;
QRect _bounds; // where on the screen to draw
float _alpha;
xColor _backgroundColor;
bool _visible; // should the overlay be drawn at all
};
#endif /* defined(__interface__Overlay__) */

View file

@ -7,6 +7,9 @@
#include "Overlays.h" #include "Overlays.h"
#include "ImageOverlay.h"
#include "TextOverlay.h"
unsigned int Overlays::_nextOverlayID = 1; unsigned int Overlays::_nextOverlayID = 1;
@ -21,7 +24,7 @@ void Overlays::init(QGLWidget* parent) {
} }
void Overlays::render() { void Overlays::render() {
foreach(ImageOverlay* thisOverlay, _imageOverlays) { foreach(Overlay* thisOverlay, _overlays) {
thisOverlay->render(); thisOverlay->render();
} }
} }
@ -36,36 +39,44 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
ImageOverlay* thisOverlay = new ImageOverlay(); ImageOverlay* thisOverlay = new ImageOverlay();
thisOverlay->init(_parent); thisOverlay->init(_parent);
thisOverlay->setProperties(properties); thisOverlay->setProperties(properties);
_imageOverlays[thisID] = thisOverlay; _overlays[thisID] = thisOverlay;
} else if (type == "text") {
thisID = _nextOverlayID;
_nextOverlayID++;
TextOverlay* thisOverlay = new TextOverlay();
thisOverlay->init(_parent);
thisOverlay->setProperties(properties);
_overlays[thisID] = thisOverlay;
} }
return thisID; return thisID;
} }
// TODO: make multi-threaded safe // TODO: make multi-threaded safe
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
if (!_imageOverlays.contains(id)) { if (!_overlays.contains(id)) {
return false; return false;
} }
ImageOverlay* thisOverlay = _imageOverlays[id]; Overlay* thisOverlay = _overlays[id];
thisOverlay->setProperties(properties); thisOverlay->setProperties(properties);
return true; return true;
} }
// TODO: make multi-threaded safe // TODO: make multi-threaded safe
void Overlays::deleteOverlay(unsigned int id) { void Overlays::deleteOverlay(unsigned int id) {
if (_imageOverlays.contains(id)) { if (_overlays.contains(id)) {
_imageOverlays.erase(_imageOverlays.find(id)); _overlays.erase(_overlays.find(id));
} }
} }
unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
QMapIterator<unsigned int, ImageOverlay*> i(_imageOverlays); QMapIterator<unsigned int, Overlay*> i(_overlays);
i.toBack(); i.toBack();
while (i.hasPrevious()) { while (i.hasPrevious()) {
i.previous(); i.previous();
unsigned int thisID = i.key(); unsigned int thisID = i.key();
ImageOverlay* thisOverlay = i.value(); Overlay* thisOverlay = i.value();
if (thisOverlay->getBounds().contains(point.x, point.y, false)) { if (thisOverlay->getVisible() && thisOverlay->getBounds().contains(point.x, point.y, false)) {
return thisID; return thisID;
} }
} }

View file

@ -10,7 +10,7 @@
#include <QScriptValue> #include <QScriptValue>
#include "ImageOverlay.h" #include "Overlay.h"
class Overlays : public QObject { class Overlays : public QObject {
Q_OBJECT Q_OBJECT
@ -35,7 +35,7 @@ public slots:
unsigned int getOverlayAtPoint(const glm::vec2& point); unsigned int getOverlayAtPoint(const glm::vec2& point);
private: private:
QMap<unsigned int, ImageOverlay*> _imageOverlays; QMap<unsigned int, Overlay*> _overlays;
static unsigned int _nextOverlayID; static unsigned int _nextOverlayID;
QGLWidget* _parent; QGLWidget* _parent;
}; };

View file

@ -0,0 +1,80 @@
//
// TextOverlay.cpp
// interface
//
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#include <QGLWidget>
#include <SharedUtil.h>
#include "TextOverlay.h"
#include "TextRenderer.h"
TextOverlay::TextOverlay() :
_leftMargin(DEFAULT_MARGIN),
_topMargin(DEFAULT_MARGIN)
{
}
TextOverlay::~TextOverlay() {
}
void TextOverlay::render() {
if (!_visible) {
return; // do nothing if we're not visible
}
const float MAX_COLOR = 255;
glColor4f(_backgroundColor.red / MAX_COLOR, _backgroundColor.green / MAX_COLOR, _backgroundColor.blue / MAX_COLOR, _alpha);
glBegin(GL_QUADS);
glVertex2f(_bounds.left(), _bounds.top());
glVertex2f(_bounds.right(), _bounds.top());
glVertex2f(_bounds.right(), _bounds.bottom());
glVertex2f(_bounds.left(), _bounds.bottom());
glEnd();
//TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false,
// EffectType effect = NO_EFFECT, int effectThickness = 1);
TextRenderer textRenderer(SANS_FONT_FAMILY, 11, 50);
const int leftAdjust = -1; // required to make text render relative to left edge of bounds
const int topAdjust = -2; // required to make text render relative to top edge of bounds
int x = _bounds.left() + _leftMargin + leftAdjust;
int y = _bounds.top() + _topMargin + topAdjust;
glColor3f(1.0f, 1.0f, 1.0f);
QStringList lines = _text.split("\n");
int lineOffset = 0;
foreach(QString thisLine, lines) {
if (lineOffset == 0) {
lineOffset = textRenderer.calculateHeight(qPrintable(thisLine));
}
lineOffset += textRenderer.draw(x, y + lineOffset, qPrintable(thisLine));
const int lineGap = 2;
lineOffset += lineGap;
}
}
void TextOverlay::setProperties(const QScriptValue& properties) {
Overlay::setProperties(properties);
QScriptValue text = properties.property("text");
if (text.isValid()) {
setText(text.toVariant().toString());
}
if (properties.property("leftMargin").isValid()) {
setLeftMargin(properties.property("leftMargin").toVariant().toInt());
}
if (properties.property("topMargin").isValid()) {
setTopMargin(properties.property("topMargin").toVariant().toInt());
}
}

View file

@ -0,0 +1,58 @@
//
// TextOverlay.h
// interface
//
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__TextOverlay__
#define __interface__TextOverlay__
// include this before QGLWidget, which includes an earlier version of OpenGL
#include "InterfaceConfig.h"
#include <QGLWidget>
#include <QImage>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRect>
#include <QScriptValue>
#include <QString>
#include <QUrl>
#include <SharedUtil.h>
#include "Overlay.h"
const int DEFAULT_MARGIN = 10;
class TextOverlay : public Overlay {
Q_OBJECT
public:
TextOverlay();
~TextOverlay();
virtual void render();
// getters
const QString& getText() const { return _text; }
int getLeftMargin() const { return _leftMargin; }
int getTopMargin() const { return _topMargin; }
// setters
void setText(const QString& text) { _text = text; }
void setLeftMargin(int margin) { _leftMargin = margin; }
void setTopMargin(int margin) { _topMargin = margin; }
virtual void setProperties(const QScriptValue& properties);
private:
QString _text;
int _leftMargin;
int _topMargin;
};
#endif /* defined(__interface__TextOverlay__) */

View file

@ -8,6 +8,8 @@
#include <QFont> #include <QFont>
#include <QPaintEngine> #include <QPaintEngine>
#include <QtDebug> #include <QtDebug>
#include <QString>
#include <QStringList>
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include "TextRenderer.h" #include "TextRenderer.h"
@ -30,10 +32,25 @@ TextRenderer::~TextRenderer() {
glDeleteTextures(_allTextureIDs.size(), _allTextureIDs.constData()); glDeleteTextures(_allTextureIDs.size(), _allTextureIDs.constData());
} }
void TextRenderer::draw(int x, int y, const char* str) { int TextRenderer::calculateHeight(const char* str) {
int maxHeight = 0;
for (const char* ch = str; *ch != 0; ch++) {
const Glyph& glyph = getGlyph(*ch);
if (glyph.textureID() == 0) {
continue;
}
if (glyph.bounds().height() > maxHeight) {
maxHeight = glyph.bounds().height();
}
}
return maxHeight;
}
int TextRenderer::draw(int x, int y, const char* str) {
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
int maxHeight = 0;
for (const char* ch = str; *ch != 0; ch++) { for (const char* ch = str; *ch != 0; ch++) {
const Glyph& glyph = getGlyph(*ch); const Glyph& glyph = getGlyph(*ch);
if (glyph.textureID() == 0) { if (glyph.textureID() == 0) {
@ -41,19 +58,23 @@ void TextRenderer::draw(int x, int y, const char* str) {
continue; continue;
} }
if (glyph.bounds().height() > maxHeight) {
maxHeight = glyph.bounds().height();
}
glBindTexture(GL_TEXTURE_2D, glyph.textureID()); glBindTexture(GL_TEXTURE_2D, glyph.textureID());
int left = x + glyph.bounds().x(); int left = x + glyph.bounds().x();
int right = x + glyph.bounds().x() + glyph.bounds().width(); int right = x + glyph.bounds().x() + glyph.bounds().width();
int bottom = y + glyph.bounds().y(); int bottom = y + glyph.bounds().y();
int top = y + glyph.bounds().y() + glyph.bounds().height(); int top = y + glyph.bounds().y() + glyph.bounds().height();
float scale = 1.0 / IMAGE_SIZE; float scale = 1.0 / IMAGE_SIZE;
float ls = glyph.location().x() * scale; float ls = glyph.location().x() * scale;
float rs = (glyph.location().x() + glyph.bounds().width()) * scale; float rs = (glyph.location().x() + glyph.bounds().width()) * scale;
float bt = glyph.location().y() * scale; float bt = glyph.location().y() * scale;
float tt = (glyph.location().y() + glyph.bounds().height()) * scale; float tt = (glyph.location().y() + glyph.bounds().height()) * scale;
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2f(ls, bt); glTexCoord2f(ls, bt);
glVertex2f(left, bottom); glVertex2f(left, bottom);
@ -64,12 +85,13 @@ void TextRenderer::draw(int x, int y, const char* str) {
glTexCoord2f(ls, tt); glTexCoord2f(ls, tt);
glVertex2f(left, top); glVertex2f(left, top);
glEnd(); glEnd();
x += glyph.width(); x += glyph.width();
} }
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
return maxHeight;
} }
int TextRenderer::computeWidth(char ch) int TextRenderer::computeWidth(char ch)

View file

@ -20,6 +20,16 @@
// a special "character" that renders as a solid block // a special "character" that renders as a solid block
const char SOLID_BLOCK_CHAR = 127; const char SOLID_BLOCK_CHAR = 127;
// the standard sans serif font family
#define SANS_FONT_FAMILY "Helvetica"
// the standard mono font family
#define MONO_FONT_FAMILY "Courier"
// the Inconsolata font family
#define INCONSOLATA_FONT_FAMILY "Inconsolata"
class Glyph; class Glyph;
class TextRenderer { class TextRenderer {
@ -33,7 +43,11 @@ public:
const QFontMetrics& metrics() const { return _metrics; } const QFontMetrics& metrics() const { return _metrics; }
void draw(int x, int y, const char* str); // returns the height of the tallest character
int calculateHeight(const char* str);
// also returns the height of the tallest character
int draw(int x, int y, const char* str);
int computeWidth(char ch); int computeWidth(char ch);
int computeWidth(const char* str); int computeWidth(const char* str);