aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordos-reis <gdr@axiomatics.org>2011-05-23 07:47:04 +0000
committerdos-reis <gdr@axiomatics.org>2011-05-23 07:47:04 +0000
commitf89c5d0438e969615c4bb9e59192cad996109665 (patch)
tree2194b79bc16642ebd10d049d237fc00118f9b837
parentf87a31a02a7b0b84ed877880d9ae22253ce89671 (diff)
downloadopen-axiom-f89c5d0438e969615c4bb9e59192cad996109665.tar.gz
Add new files
-rw-r--r--src/gui/conversation.C222
-rw-r--r--src/gui/conversation.h152
-rw-r--r--src/gui/debate.C44
-rw-r--r--src/gui/debate.h56
-rw-r--r--src/gui/gui.pro.in4
-rw-r--r--src/gui/main-window.C9
-rw-r--r--src/gui/main-window.h4
-rw-r--r--src/gui/main.C4
8 files changed, 489 insertions, 6 deletions
diff --git a/src/gui/conversation.C b/src/gui/conversation.C
new file mode 100644
index 00000000..1938dbb7
--- /dev/null
+++ b/src/gui/conversation.C
@@ -0,0 +1,222 @@
+// Copyright (C) 2011, Gabriel Dos Reis.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of OpenAxiom. nor the names of its contributors
+// may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string>
+#include <sstream>
+#include <iostream>
+
+#include <QScrollBar>
+#include "conversation.h"
+#include "debate.h"
+
+namespace OpenAxiom {
+ // -- Question --
+ Question::Question(Exchange& e) : QLineEdit(&e) { }
+
+ // -- Answer --
+ Answer::Answer(Exchange& e) : QLabel(&e) { }
+
+
+ // -- Exchange --
+ // Amount of pixel spacing between the query and reply areas.
+ const int spacing = 0;
+
+ // Margin around query and reply areas.
+ const int margin = 2;
+
+ QSize Exchange::sizeHint() const {
+ QSize sz = question()->frameSize();
+ sz.rwidth() += 2 * margin;
+ sz.rheight() += answer()->frameSize().height() + spacing + 2 * margin;
+ return sz;
+ }
+
+ QSize Exchange::minimumSizeHint() const {
+ QSize sz = question()->frameSize();
+ sz.rwidth() += 2 * margin;
+ if (not answer()->isHidden())
+ sz.rheight() += answer()->frameSize().height() + spacing;
+ sz.rheight() += 2 * margin;
+ return sz;
+ }
+
+ // Return a monospace font
+ QFont
+ monospace_font() {
+ QFont f("Courier");
+ f.setStyleHint(QFont::TypeWriter);
+ return f;
+ }
+
+ // Measurement in pixel of the em unit in the given font metrics.
+ static QSize
+ em_metrics(const QFontMetrics& fm) {
+ return QSize(fm.width(QLatin1Char('m')), fm.height());
+ }
+
+ // Measurement in pixel of the em unit in the given font `f'.
+ QSize em_metrics(const QFont& f) {
+ return em_metrics(QFontMetrics(f));
+ }
+
+ // Dress the query area with initial properties.
+ static void
+ prepare_query_widget(QLineEdit* w) {
+ w->setFrame(false);
+ w->setFont(monospace_font());
+ QSize em = em_metrics(w->fontMetrics());
+ w->setGeometry(margin, margin,
+ question_columns * em.width(), em.height());
+ }
+
+ // Dress the reply aread with initial properties.
+ static void
+ prepare_reply_widget(QLabel* w, const QRect& below) {
+ w->setFont(monospace_font());
+ w->setGeometry(below.x(), below.height() + spacing,
+ below.width(), 2 * w->fontMetrics().height());
+ w->hide(); // nothing to show yet
+ }
+
+ // -- Exchange --
+ Exchange::Exchange(Conversation& conv, int n)
+ : QFrame(&conv), no(n), query(*this), reply(*this) {
+ // 1. Construct the query area.
+ prepare_query_widget(question());
+
+ // 2. Construct the response area.
+ prepare_reply_widget(answer(), question()->geometry());
+
+ // 3. Construct the whole frame
+ QSize qs = question()->frameSize();
+ QSize rs = answer()->frameSize();
+ resize(qs.width() + 2 * margin, qs.height() + rs.height() + 2 * margin);
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ setLineWidth(1);
+ // 4.
+ connect(&query, SIGNAL(returnPressed()),
+ this, SLOT(reply_to_query()));
+ }
+
+ static QString
+ parenthesize(int n) {
+ std::ostringstream os;
+ os << '(' << n << ')';
+ return QString::fromStdString(os.str());
+ }
+
+ Conversation* Exchange::conversation() {
+ return &dynamic_cast<Conversation&>(*parentWidget());
+ }
+
+ Debate* Exchange::debate() {
+ return conversation()->debate();
+ }
+
+ void
+ Exchange::reply_to_query() {
+ QString input = question()->text().trimmed();
+ if (input.isEmpty())
+ return;
+ QString ans = parenthesize(number()) + " " + input;
+ answer()->show();
+ answer()->setText(ans);
+ debate()->ensureWidgetVisible(answer());
+ debate()->horizontalScrollBar()->setValue(0);
+ conversation()->next(this)->question()
+ ->setFocus(Qt::OtherFocusReason);
+ }
+
+ // ------------------
+ // -- Conversation --
+ // -------------------
+
+ static void resize_if_necessary(Conversation& conv) {
+ QSize sz = conv.sizeHint();
+ if (sz.height() > conv.height())
+ conv.resize(conv.width(), sz.height());
+ }
+
+ static void debug_engine(Conversation& conv) {
+ std::cerr << "# conversations: " << conv.length()
+ << std::endl;
+ QSize sz = conv.sizeHint();
+ std::cerr << "size: " << sz.width() << ", " << sz.height()
+ << std::endl;
+ }
+
+ Conversation::Conversation(Debate& parent)
+ : QWidget(&parent), group(parent) {
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ QSize sz = new_topic()->frameSize();
+ setMinimumSize(sz.width(), 10 * sz.height());
+ }
+
+ Conversation::~Conversation() {
+ for (int i = children.size() -1 ; i >= 0; --i)
+ delete children[i];
+ }
+
+ QSize Conversation::sizeHint() const {
+ QSize sz(0,0);
+ for (int i = 0; i < length(); ++i) {
+ QSize s = children[i]->sizeHint();
+ if (s.width() > sz.width())
+ sz.setWidth(s.width());
+ sz.rheight() += s.height();
+ }
+ return sz;
+ }
+
+ Exchange*
+ Conversation::new_topic() {
+ QPoint loc(0,0);
+ if (not fresh()) {
+ Exchange* last = children.back();
+ loc = last->geometry().bottomLeft();
+ }
+ Exchange* w = new Exchange(*this, length() + 1);
+ w->setVisible(true);
+ w->move(loc);
+ children.push_back(w);
+ resize_if_necessary(*this);
+ debug_engine(*this);
+ return w;
+ }
+
+
+ Exchange*
+ Conversation::next(Exchange* w) {
+ if (w == 0 or w->number() == length())
+ return new_topic();
+ return children[w->number()];
+ }
+}
diff --git a/src/gui/conversation.h b/src/gui/conversation.h
new file mode 100644
index 00000000..d949e9d6
--- /dev/null
+++ b/src/gui/conversation.h
@@ -0,0 +1,152 @@
+// Copyright (C) 2011, Gabriel Dos Reis.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of OpenAxiom. nor the names of its contributors
+// may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef OPENAXIOM_CONVERSATION_INCLUDED
+#define OPENAXIOM_CONVERSATION_INCLUDED
+
+#include <QFrame>
+#include <QLineEdit>
+#include <QLabel>
+#include <QFont>
+#include <vector>
+
+namespace OpenAxiom {
+ // A conversation is a set of exchanges. An exchange is a question
+ // followed by an answer. A conversation that takes place in a
+ // a certain frame is a debate.
+ class Debate;
+ class Conversation;
+ class Exchange;
+ class Question;
+ class Answer;
+
+ // -- A question is just a one-liner query.
+ class Question : public QLineEdit {
+ public:
+ explicit Question(Exchange&);
+ };
+
+ class Answer : public QLabel {
+ public:
+ explicit Answer(Exchange&);
+ };
+
+ // -- Elemental conversation widget
+ // -- A basic interaction consists of a query, a reply, and the
+ // -- the type of the reply.
+ class Exchange : public QFrame {
+ Q_OBJECT;
+ public:
+ Exchange(Conversation&, int);
+
+ // Return the parent widget of this conversation topic
+ Conversation* conversation();
+ Debate* debate();
+
+ // The widget holding the query area
+ Question* question() { return &query; }
+ const Question* question() const { return &query; }
+
+ // The widget holding the reply area.
+ Answer* answer() { return &reply; }
+ const Answer* answer() const { return &reply; }
+
+ // Conversion number
+ int number() const { return no; }
+
+ // Reimplement positiion management.
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ protected:
+ // void resizeEvent(QResizeEvent*);
+
+ private:
+ const int no;
+ Question query;
+ Answer reply;
+
+ private slots:
+ void reply_to_query();
+ };
+
+ // -- Set of conversations that make up a session.
+ // -- We remember and number each topic so that we
+ // -- can go back in the conversation set and reevaluate
+ // -- queries.
+ class Conversation : public QWidget {
+ Q_OBJECT;
+ public:
+ explicit Conversation(Debate&);
+ ~Conversation();
+
+ // Holds if this conversation just started.
+ bool fresh() const { return children.empty(); }
+
+ // Number of exchanges in this conversation
+ int length() const { return children.size(); }
+
+ // Return the `i'-th conversation in this set, if any.
+ Exchange* operator[](int) const;
+
+ // Start a new conversation topic.
+ Exchange* new_topic();
+
+ // Override QWidegt::sizeHint. Return the cumulative sizes
+ // of all conversations so far.
+ QSize sizeHint() const;
+
+ // Return the parent engine widget.
+ Debate* debate() { return &group; }
+
+ public slots:
+ // Return the topic following a given topic in this set of conversations
+ Exchange* next(Exchange*);
+
+ private:
+ typedef std::vector<Exchange*> Children;
+ Debate& group;
+ Children children;
+ };
+
+ // Default number of characters per question line.
+ const int question_columns = 80;
+
+ QFont monospace_font();
+ QSize em_metrics(const QFont&);
+}
+
+#endif // OPENAXIOM_CONVERSATION_INCLUDED
+
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/gui/debate.C b/src/gui/debate.C
new file mode 100644
index 00000000..a4f289c1
--- /dev/null
+++ b/src/gui/debate.C
@@ -0,0 +1,44 @@
+// Copyright (C) 2011, Gabriel Dos Reis.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of OpenAxiom. nor the names of its contributors
+// may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <QScrollBar>
+#include "debate.h"
+
+namespace OpenAxiom {
+
+ Debate::Debate(QWidget* parent)
+ : QScrollArea(parent), conv(*this) {
+ setViewportMargins(0, 0, 0, 0);
+ setWidget(&conv);
+ }
+
+ Debate::~Debate() { }
+}
diff --git a/src/gui/debate.h b/src/gui/debate.h
new file mode 100644
index 00000000..86016909
--- /dev/null
+++ b/src/gui/debate.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2011, Gabriel Dos Reis.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of OpenAxiom. nor the names of its contributors
+// may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef OPENAXIOM_DEBATE_INCLUDED
+#define OPENAXIOM_DEBATE_INCLUDED
+
+#include <QWidget>
+#include <QFontMetrics>
+#include <QScrollArea>
+#include "conversation.h"
+
+namespace OpenAxiom {
+
+ class Debate : public QScrollArea {
+ public:
+ explicit Debate(QWidget*);
+ ~Debate();
+
+ private:
+ Conversation conv;
+ };
+}
+
+#endif // OPENAXIOM_DEBATE_INCLUDED
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/gui/gui.pro.in b/src/gui/gui.pro.in
index 6ea0d2b7..8159a926 100644
--- a/src/gui/gui.pro.in
+++ b/src/gui/gui.pro.in
@@ -12,12 +12,12 @@ TARGET = gui
VPATH += @srcdir@
## Our headers
-HEADERS += main-window.h
+HEADERS += conversation.h main-window.h debate.h
INCLUDEPATH += @srcdir@
DEPENDPATH += @srcdir@
## Source files
-SOURCES += main-window.C main.C
+SOURCES += conversation.C main-window.C debate.C main.C
## Additional support libraries
LIBS += $$OA_LIB
diff --git a/src/gui/main-window.C b/src/gui/main-window.C
index 9409fde8..6e0e16a7 100644
--- a/src/gui/main-window.C
+++ b/src/gui/main-window.C
@@ -31,18 +31,23 @@
#include <QMenuBar>
#include <QAction>
+#include <QScrollArea>
+#include "engine-widget.h"
#include "main-window.h"
namespace OpenAxiom {
- MainWindow::MainWindow() {
+
+ MainWindow::MainWindow() : tabs(this) {
+ setCentralWidget(&tabs);
+ tabs.addTab(new Debate(&tabs), "Main Frame");
QMenu* file = menuBar()->addMenu(tr("&File"));
QAction* action = new QAction(tr("Quit"), this);
file->addAction(action);
action->setShortcut(tr("Ctrl+Q"));
connect(action, SIGNAL(triggered()), this, SLOT(close()));
}
-
+
MainWindow::~MainWindow() {
}
}
diff --git a/src/gui/main-window.h b/src/gui/main-window.h
index fb891504..af9d3d87 100644
--- a/src/gui/main-window.h
+++ b/src/gui/main-window.h
@@ -33,6 +33,7 @@
#define OPENAXIOM_GUI_MAIN_WINDOW_INCLUDED
#include <QMainWindow>
+#include <QTabWidget>
namespace OpenAxiom {
// -- Main application window --
@@ -41,6 +42,9 @@ namespace OpenAxiom {
public:
MainWindow();
~MainWindow();
+
+ private:
+ QTabWidget tabs;
};
}
diff --git a/src/gui/main.C b/src/gui/main.C
index 46a412df..3f05c12e 100644
--- a/src/gui/main.C
+++ b/src/gui/main.C
@@ -36,7 +36,7 @@ int
main(int argc, char* argv[]) {
using namespace OpenAxiom;
QApplication app(argc, argv);
- MainWindow mainWin;
- mainWin.show();
+ MainWindow main_win;
+ main_win.show();
return app.exec();
}