Skip to content

Commit

Permalink
Client|Widgets: Working on LogWidget
Browse files Browse the repository at this point in the history
This is incomplete work presently, however the basic building blocks
are in place: log entries are received via a sink, they are wrapped
to multiple lines, and are then composed for GL drawing using
GLTextComposer. The entries near the visible range are kept ready for
rendering on a separate atlas.

Todo: Fix eventual corruption / overdraw / atlas misbehavior
Todo: Text styling (handle styling escape symbols in Font)
Todo: Performance -- too many calls to measure text's visible widths
Todo: Cleanup of LogWidget implementation
  • Loading branch information
skyjake committed May 22, 2013
1 parent 6c734bb commit 3a86a50
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 140 deletions.
1 change: 1 addition & 0 deletions doomsday/client/client.pro
Expand Up @@ -367,6 +367,7 @@ DENG_HEADERS += \
include/ui/widgets/legacywidget.h \
include/ui/widgets/lineeditwidget.h \
include/ui/widgets/logwidget.h \
include/ui/widgets/styledlogsinkformatter.h \
include/ui/widgets/taskbarwidget.h \
include/ui/widgets/widgetactions.h \
include/ui/windowsystem.h \
Expand Down
4 changes: 2 additions & 2 deletions doomsday/client/data/defaultstyle.pack/fonts.dei
Expand Up @@ -18,7 +18,7 @@ group {

font default {
family: Lucida Grande
size: 24pt
size: 18pt
weight: normal
style: normal
}
Expand All @@ -37,7 +37,7 @@ font title inherits default {
}

group log {
font normal inherits monospace {}
font normal inherits default {}
}

group editor {
Expand Down
2 changes: 2 additions & 0 deletions doomsday/client/include/ui/widgets/fontlinewrapping.h
Expand Up @@ -39,6 +39,8 @@ class FontLineWrapping : public de::shell::ILineWrapping
bool isEmpty() const;
void clear();
void wrapTextToWidth(de::String const &text, int maxWidth);

de::String const &text() const;
de::shell::WrappedLine line(int index) const;
int width() const;
int height() const;
Expand Down
4 changes: 4 additions & 0 deletions doomsday/client/include/ui/widgets/gltextcomposer.h
Expand Up @@ -75,6 +75,10 @@ class GLTextComposer
*/
void release();

void makeVertices(Vertices &triStrip,
de::Vector2i const &topLeft,
Alignment const &lineAlign);

/**
* Generates vertices for all the text lines and concatenates them
* onto the existing triangle strip in @a triStrip.
Expand Down
6 changes: 5 additions & 1 deletion doomsday/client/include/ui/widgets/logwidget.h
Expand Up @@ -70,7 +70,7 @@ class LogWidget : public QObject, public GuiWidget
void scroll(int to);

// Events.
void initialize();
void viewResized();
void draw();
bool handleEvent(de::Event const &event);

Expand All @@ -84,6 +84,10 @@ public slots:
void scrollPositionChanged(int pos);
void scrollMaxChanged(int maximum);

protected:
void glInit();
void glDeinit();

private:
DENG2_PRIVATE(d)
};
Expand Down
39 changes: 39 additions & 0 deletions doomsday/client/include/ui/widgets/styledlogsinkformatter.h
@@ -0,0 +1,39 @@
/** @file styledlogsinkformatter.h
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef STYLEDLOGSINKFORMATTER_H
#define STYLEDLOGSINKFORMATTER_H

#include <de/LogSink>
#include <de/String>

/**
* Formats log entries for styled output.
*/
class StyledLogSinkFormatter : public de::LogSink::IFormatter
{
public:
Lines logEntryToTextLines(de::LogEntry const &entry)
{
// This will form a single long line. The line wrapper will
// then determine how to wrap it onto the available width.
return Lines() << entry.asText(de::LogEntry::Styled);
}
};

#endif // STYLEDLOGSINKFORMATTER_H
8 changes: 8 additions & 0 deletions doomsday/client/src/ui/clientwindow.cpp
Expand Up @@ -38,6 +38,7 @@
#include "ui/widgets/taskbarwidget.h"
#include "ui/widgets/lineeditwidget.h"
#include "ui/widgets/consolecommandwidget.h"
#include "ui/widgets/logwidget.h"
#include "ui/mouse_qt.h"

#include "dd_main.h"
Expand Down Expand Up @@ -96,6 +97,13 @@ DENG2_PIMPL(ClientWindow),
root.add(test);
root.setFocus(test);

LogWidget *log = new LogWidget;
log->rule()
.setInput(Rule::Left, root.viewLeft())
.setInput(Rule::Bottom, test->rule().top())
.setInput(Rule::Top, root.viewTop() + 200);
root.add(log);

// Initially the widget is disabled. It will be enabled when the window
// is visible and ready to be drawn.
legacy->disable();
Expand Down
47 changes: 32 additions & 15 deletions doomsday/client/src/ui/widgets/fontlinewrapping.cpp
Expand Up @@ -24,7 +24,13 @@ using namespace de::shell;
DENG2_PIMPL_NOREF(FontLineWrapping)
{
Font const *font;
QList<WrappedLine> lines;
struct Line {
WrappedLine line;
int width;

Line(WrappedLine const &ln = WrappedLine(Range()), int w = 0) : line(ln), width(w) {}
};
QList<Line> lines;
String text;

Instance() : font(0) {}
Expand All @@ -51,6 +57,11 @@ DENG2_PIMPL_NOREF(FontLineWrapping)
}
return 0;
}

void appendLine(Range const &range)
{
lines.append(Line(WrappedLine(range), rangeVisibleWidth(range)));
}
};

FontLineWrapping::FontLineWrapping() : d(new Instance)
Expand Down Expand Up @@ -98,9 +109,11 @@ void FontLineWrapping::wrapTextToWidth(String const &text, int maxWidth)
forever
{
// Quick check: does the remainder fit?
if(d->rangeVisibleWidth(Range(begin, text.size())) <= maxWidth)
Range range(begin, text.size());
int visWidth = d->rangeVisibleWidth(range);
if(visWidth <= maxWidth)
{
d->lines.append(WrappedLine(Range(begin, text.size())));
d->lines.append(Instance::Line(WrappedLine(Range(begin, text.size())), visWidth));
break;
}

Expand All @@ -119,12 +132,15 @@ void FontLineWrapping::wrapTextToWidth(String const &text, int maxWidth)
}
}

DENG2_ASSERT(end != text.size());

/*
if(end == text.size())
{
// Out of characters; time to stop.
d->lines.append(WrappedLine(Range(begin, text.size())));
d->appendLine(Range(begin, text.size()));
break;
}
}*/

// Find a good (whitespace) break point.
while(!text.at(end).isSpace())
Expand All @@ -140,37 +156,38 @@ void FontLineWrapping::wrapTextToWidth(String const &text, int maxWidth)
if(text.at(end) == newline)
{
// The newline will be omitted from the wrapped lines.
d->lines.append(WrappedLine(Range(begin, end)));
d->appendLine(Range(begin, end));
begin = end + 1;
}
else
{
while(text.at(end).isSpace()) ++end;
d->lines.append(WrappedLine(Range(begin, end)));
d->appendLine(Range(begin, end));
begin = end;
//while(text.at(begin).isSpace()) ++begin;
}
}

// Mark the final line.
d->lines.last().isFinal = true;
d->lines.last().line.isFinal = true;
}

String const &FontLineWrapping::text() const
{
return d->text;
}

WrappedLine FontLineWrapping::line(int index) const
{
DENG2_ASSERT(index >= 0 && index < height());
return d->lines[index];
return d->lines[index].line;
}

int FontLineWrapping::width() const
{
if(!d->font) return 0;

int w = 0;
for(int i = 0; i < d->lines.size(); ++i)
{
WrappedLine const &span = d->lines[i];
w = de::max(w, d->rangeVisibleWidth(span.range));
w = de::max(w, d->lines[i].width);
}
return w;
}
Expand Down Expand Up @@ -230,7 +247,7 @@ Vector2i FontLineWrapping::charTopLeftInPixels(int line, int charIndex)
{
if(line >= height()) return Vector2i();

WrappedLine const span = d->lines[line];
WrappedLine const span = d->lines[line].line;
Range const range(span.range.start, de::min(span.range.end, span.range.start + charIndex));

Vector2i cp;
Expand Down
11 changes: 8 additions & 3 deletions doomsday/client/src/ui/widgets/gltextcomposer.cpp
Expand Up @@ -91,8 +91,6 @@ DENG2_PIMPL(GLTextComposer)
Line &line = lines[i];
line.range = span.range;
line.id = atlas->alloc(font->rasterize(part));

//qDebug() << lines.back().asText() << part;
}

// Remove the excess lines.
Expand Down Expand Up @@ -144,6 +142,13 @@ bool GLTextComposer::update()
return d->allocLines();
}

void GLTextComposer::makeVertices(Vertices &triStrip,
Vector2i const &topLeft,
Alignment const &lineAlign)
{
makeVertices(triStrip, Rectanglei(topLeft, topLeft), AlignTop | AlignLeft, lineAlign);
}

void GLTextComposer::makeVertices(Vertices &triStrip,
Rectanglei const &rect,
Alignment const &alignInRect,
Expand All @@ -167,7 +172,7 @@ void GLTextComposer::makeVertices(Vertices &triStrip,
{
p.y += int(rect.height()) - contentSize.y;
}
else
else if(!alignInRect.testFlag(AlignTop))
{
p.y += (int(rect.height()) - contentSize.y) / 2;
}
Expand Down

0 comments on commit 3a86a50

Please sign in to comment.