mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 07:48:08 +02:00
implement text overlay support
This commit is contained in:
parent
0a9f9a7c7a
commit
ef11865d24
12 changed files with 382 additions and 122 deletions
|
@ -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", {
|
||||
x: 100,
|
||||
y: 100,
|
||||
|
@ -97,6 +110,7 @@ function scriptEnding() {
|
|||
}
|
||||
Overlays.deleteOverlay(thumb);
|
||||
Overlays.deleteOverlay(slider);
|
||||
Overlays.deleteOverlay(text);
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
@ -132,10 +146,14 @@ function mouseMoveEvent(event) {
|
|||
}
|
||||
}
|
||||
function mousePressEvent(event) {
|
||||
var clickedText = false;
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||
if (clickedOverlay == thumb) {
|
||||
movingSlider = true;
|
||||
thumbClickOffsetX = event.x - thumbX;
|
||||
} else if (clickedOverlay == text) {
|
||||
Overlays.editOverlay(text, { text: "you clicked here:\n " + event.x + "," + event.y } );
|
||||
clickedText = true;
|
||||
} else {
|
||||
for (s = 0; s < numberOfSwatches; 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) {
|
||||
|
|
|
@ -19,15 +19,6 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
#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);
|
||||
|
||||
float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos);
|
||||
|
|
|
@ -14,23 +14,13 @@
|
|||
#include <SharedUtil.h>
|
||||
|
||||
ImageOverlay::ImageOverlay() :
|
||||
_parent(NULL),
|
||||
_textureID(0),
|
||||
_alpha(DEFAULT_ALPHA),
|
||||
_backgroundColor(DEFAULT_BACKGROUND_COLOR),
|
||||
_visible(true),
|
||||
_renderImage(false),
|
||||
_textureBound(false),
|
||||
_wantClipFromImage(false)
|
||||
{
|
||||
}
|
||||
|
||||
void ImageOverlay::init(QGLWidget* parent) {
|
||||
qDebug() << "ImageOverlay::init() parent=" << parent;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
|
||||
ImageOverlay::~ImageOverlay() {
|
||||
if (_parent && _textureID) {
|
||||
// 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) {
|
||||
//qDebug() << "ImageOverlay::setProperties()... properties=" << &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();
|
||||
}
|
||||
Overlay::setProperties(properties);
|
||||
|
||||
QScriptValue subImageBounds = properties.property("subImage");
|
||||
if (subImageBounds.isValid()) {
|
||||
QRect oldSubImageRect = _fromImage;
|
||||
|
@ -183,26 +138,6 @@ void ImageOverlay::setProperties(const QScriptValue& properties) {
|
|||
if (imageURL.isValid()) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,43 +22,24 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
const xColor DEFAULT_BACKGROUND_COLOR = { 255, 255, 255 };
|
||||
const float DEFAULT_ALPHA = 0.7f;
|
||||
#include "Overlay.h"
|
||||
|
||||
class ImageOverlay : QObject {
|
||||
class ImageOverlay : public Overlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImageOverlay();
|
||||
~ImageOverlay();
|
||||
void init(QGLWidget* parent);
|
||||
void render();
|
||||
virtual void render();
|
||||
|
||||
//public slots:
|
||||
// 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 xColor& getBackgroundColor() const { return _backgroundColor; }
|
||||
float getAlpha() const { return _alpha; }
|
||||
const QUrl& getImageURL() const { return _imageURL; }
|
||||
|
||||
// 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 setBackgroundColor(const xColor& color) { _backgroundColor = color; }
|
||||
void setAlpha(float alpha) { _alpha = alpha; }
|
||||
void setImageURL(const QUrl& url);
|
||||
void setProperties(const QScriptValue& properties);
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
private slots:
|
||||
void replyFinished(QNetworkReply* reply); // we actually want to hide this...
|
||||
|
@ -66,14 +47,9 @@ private slots:
|
|||
private:
|
||||
|
||||
QUrl _imageURL;
|
||||
QGLWidget* _parent;
|
||||
QImage _textureImage;
|
||||
GLuint _textureID;
|
||||
QRect _bounds; // where on the screen to draw
|
||||
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 _textureBound; // has the texture been bound
|
||||
bool _wantClipFromImage;
|
||||
|
|
88
interface/src/ui/Overlay.cpp
Normal file
88
interface/src/ui/Overlay.cpp
Normal 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());
|
||||
}
|
||||
}
|
64
interface/src/ui/Overlay.h
Normal file
64
interface/src/ui/Overlay.h
Normal 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__) */
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
|
||||
#include "Overlays.h"
|
||||
#include "ImageOverlay.h"
|
||||
#include "TextOverlay.h"
|
||||
|
||||
|
||||
unsigned int Overlays::_nextOverlayID = 1;
|
||||
|
||||
|
@ -21,7 +24,7 @@ void Overlays::init(QGLWidget* parent) {
|
|||
}
|
||||
|
||||
void Overlays::render() {
|
||||
foreach(ImageOverlay* thisOverlay, _imageOverlays) {
|
||||
foreach(Overlay* thisOverlay, _overlays) {
|
||||
thisOverlay->render();
|
||||
}
|
||||
}
|
||||
|
@ -36,36 +39,44 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
|||
ImageOverlay* thisOverlay = new ImageOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: make multi-threaded safe
|
||||
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
||||
if (!_imageOverlays.contains(id)) {
|
||||
if (!_overlays.contains(id)) {
|
||||
return false;
|
||||
}
|
||||
ImageOverlay* thisOverlay = _imageOverlays[id];
|
||||
Overlay* thisOverlay = _overlays[id];
|
||||
thisOverlay->setProperties(properties);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: make multi-threaded safe
|
||||
void Overlays::deleteOverlay(unsigned int id) {
|
||||
if (_imageOverlays.contains(id)) {
|
||||
_imageOverlays.erase(_imageOverlays.find(id));
|
||||
if (_overlays.contains(id)) {
|
||||
_overlays.erase(_overlays.find(id));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||
QMapIterator<unsigned int, ImageOverlay*> i(_imageOverlays);
|
||||
QMapIterator<unsigned int, Overlay*> i(_overlays);
|
||||
i.toBack();
|
||||
while (i.hasPrevious()) {
|
||||
i.previous();
|
||||
unsigned int thisID = i.key();
|
||||
ImageOverlay* thisOverlay = i.value();
|
||||
if (thisOverlay->getBounds().contains(point.x, point.y, false)) {
|
||||
Overlay* thisOverlay = i.value();
|
||||
if (thisOverlay->getVisible() && thisOverlay->getBounds().contains(point.x, point.y, false)) {
|
||||
return thisID;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <QScriptValue>
|
||||
|
||||
#include "ImageOverlay.h"
|
||||
#include "Overlay.h"
|
||||
|
||||
class Overlays : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -35,7 +35,7 @@ public slots:
|
|||
unsigned int getOverlayAtPoint(const glm::vec2& point);
|
||||
|
||||
private:
|
||||
QMap<unsigned int, ImageOverlay*> _imageOverlays;
|
||||
QMap<unsigned int, Overlay*> _overlays;
|
||||
static unsigned int _nextOverlayID;
|
||||
QGLWidget* _parent;
|
||||
};
|
||||
|
|
80
interface/src/ui/TextOverlay.cpp
Normal file
80
interface/src/ui/TextOverlay.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
58
interface/src/ui/TextOverlay.h
Normal file
58
interface/src/ui/TextOverlay.h
Normal 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__) */
|
|
@ -8,6 +8,8 @@
|
|||
#include <QFont>
|
||||
#include <QPaintEngine>
|
||||
#include <QtDebug>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include "TextRenderer.h"
|
||||
|
@ -30,10 +32,25 @@ TextRenderer::~TextRenderer() {
|
|||
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);
|
||||
|
||||
int maxHeight = 0;
|
||||
for (const char* ch = str; *ch != 0; ch++) {
|
||||
const Glyph& glyph = getGlyph(*ch);
|
||||
if (glyph.textureID() == 0) {
|
||||
|
@ -41,19 +58,23 @@ void TextRenderer::draw(int x, int y, const char* str) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (glyph.bounds().height() > maxHeight) {
|
||||
maxHeight = glyph.bounds().height();
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, glyph.textureID());
|
||||
|
||||
|
||||
int left = x + glyph.bounds().x();
|
||||
int right = x + glyph.bounds().x() + glyph.bounds().width();
|
||||
int bottom = y + glyph.bounds().y();
|
||||
int top = y + glyph.bounds().y() + glyph.bounds().height();
|
||||
|
||||
|
||||
float scale = 1.0 / IMAGE_SIZE;
|
||||
float ls = glyph.location().x() * scale;
|
||||
float rs = (glyph.location().x() + glyph.bounds().width()) * scale;
|
||||
float bt = glyph.location().y() * scale;
|
||||
float tt = (glyph.location().y() + glyph.bounds().height()) * scale;
|
||||
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(ls, bt);
|
||||
glVertex2f(left, bottom);
|
||||
|
@ -64,12 +85,13 @@ void TextRenderer::draw(int x, int y, const char* str) {
|
|||
glTexCoord2f(ls, tt);
|
||||
glVertex2f(left, top);
|
||||
glEnd();
|
||||
|
||||
|
||||
x += glyph.width();
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
int TextRenderer::computeWidth(char ch)
|
||||
|
|
|
@ -20,6 +20,16 @@
|
|||
// a special "character" that renders as a solid block
|
||||
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 TextRenderer {
|
||||
|
@ -33,7 +43,11 @@ public:
|
|||
|
||||
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(const char* str);
|
||||
|
|
Loading…
Reference in a new issue