From ce9afecdbd0be5d58b5fb502effc64f42090c992 Mon Sep 17 00:00:00 2001 From: James Turner Date: Fri, 8 Feb 2013 19:39:41 +0000 Subject: [PATCH] Support a log-list widget in PUI. Add a puaListBox which can show the contents of a log-buffer. Currently only two buffer sources are supported more to follow (and the dialog XML updates). --- src/GUI/FGPUIDialog.cxx | 68 ++++++++++++++++++++++++++++++++++++++ src/GUI/FGPUIDialog.hxx | 8 +++++ src/GUI/new_gui.cxx | 1 + src/Scripting/NasalSys.cxx | 5 +++ src/Scripting/NasalSys.hxx | 11 +++++- 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/GUI/FGPUIDialog.cxx b/src/GUI/FGPUIDialog.cxx index 70ba763f4..33cbc5288 100644 --- a/src/GUI/FGPUIDialog.cxx +++ b/src/GUI/FGPUIDialog.cxx @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include
@@ -162,6 +164,25 @@ private: bool _inHit; }; +class LogList : public puaList, public FGPUIDialog::ActiveWidget, public GUI_ID { +public: + LogList(int x1, int y1, int x2, int y2, int sw) : + puaList(x1, y1, x2, y2, sw), + GUI_ID(FGCLASS_LOGLIST) + { + m_buffer = NULL; + m_stamp = 0; + } + + void setBuffer(simgear::BufferedLogCallback* buf); + + virtual void update(); +private: + std::vector m_items; + simgear::BufferedLogCallback* m_buffer; + unsigned int m_stamp; +}; + class fgSelectBox : public fgValueList, public puaSelectBox { public: fgSelectBox(int x1, int y1, int x2, int y2, SGPropertyNode *p) : @@ -749,6 +770,10 @@ FGPUIDialog::update () _conditionalObjects[j]->update(this); } + for (unsigned int i = 0; i < _activeWidgets.size(); i++) { + _activeWidgets[i]->update(); + } + if (_needsRelayout) { relayout(); } @@ -1024,6 +1049,21 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh ScrolledWaypointList* obj = new ScrolledWaypointList(x, y, width, height); setupObject(obj, props); return obj; + + } else if (type == "loglist") { + LogList* obj = new LogList(x, y, width, height, 20); + string logClass = props->getStringValue("logclass"); + if (logClass == "terrasync") { + simgear::SGTerraSync* tsync = (simgear::SGTerraSync*) globals->get_subsystem("terrasync"); + obj->setBuffer(tsync->log()); + } else { + FGNasalSys* nasal = (FGNasalSys*) globals->get_subsystem("nasal"); + obj->setBuffer(nasal->log()); + } + + setupObject(obj, props); + _activeWidgets.push_back(obj); + return obj; } else { return 0; } @@ -1474,6 +1514,34 @@ fgList::update() setTopItem(top); } +//////////////////////////////////////////////////////////////////////// +// Implementation of fgLogList +//////////////////////////////////////////////////////////////////////// + +void LogList::update() +{ + if (!m_buffer) return; + + if (m_stamp != m_buffer->stamp()) { + m_stamp = m_buffer->threadsafeCopy(m_items); + m_items.push_back(NULL); // terminator value + newList((char**) m_items.data()); + setTopItem(m_items.size() - 1); // scroll to bottom of list + } +} + +void LogList::setBuffer(simgear::BufferedLogCallback* buf) +{ + m_buffer = buf; + m_stamp = m_buffer->stamp() - 1; // force an update + update(); +} + +//////////////////////////////////////////////////////////////////////// +// Implementation of fgComboBox +//////////////////////////////////////////////////////////////////////// + + void fgComboBox::update() { if (_inHit) { diff --git a/src/GUI/FGPUIDialog.hxx b/src/GUI/FGPUIDialog.hxx index 52ea117b2..a21c4ec8c 100644 --- a/src/GUI/FGPUIDialog.hxx +++ b/src/GUI/FGPUIDialog.hxx @@ -100,6 +100,12 @@ public: void setNeedsLayout() { _needsRelayout = true; } + + class ActiveWidget + { + public: + virtual void update() = 0; + }; private: enum { @@ -191,6 +197,8 @@ private: typedef SGSharedPtr ConditionalObjectRef; std::vector _conditionalObjects; + + std::vector _activeWidgets; }; #endif // __DIALOG_HXX diff --git a/src/GUI/new_gui.cxx b/src/GUI/new_gui.cxx index 864352b1a..eff8bbe2f 100644 --- a/src/GUI/new_gui.cxx +++ b/src/GUI/new_gui.cxx @@ -142,6 +142,7 @@ NewGUI::unbind () void NewGUI::update (double delta_time_sec) { + SG_UNUSED(delta_time_sec); map::iterator iter = _active_dialogs.begin(); for(/**/; iter != _active_dialogs.end(); iter++) iter->second->update(); diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 6ae142a75..537adf1f5 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include "NasalSys.hxx" #include "NasalPositioned.hxx" @@ -109,6 +110,10 @@ FGNasalSys::FGNasalSys() _gcHash = naNil(); _nextGCKey = 0; // Any value will do _callCount = 0; + + _log = new simgear::BufferedLogCallback(SG_NASAL, SG_INFO); + _log->truncateAt(255); + sglog().addCallback(_log); } // Utility. Sets a named key in a hash by C string, rather than nasal diff --git a/src/Scripting/NasalSys.hxx b/src/Scripting/NasalSys.hxx index 83efde6e4..7fa3fb7ae 100644 --- a/src/Scripting/NasalSys.hxx +++ b/src/Scripting/NasalSys.hxx @@ -16,6 +16,8 @@ class FGNasalScript; class FGNasalListener; class SGCondition; +namespace simgear { class BufferedLogCallback; } + /** Nasal model data container. * load and unload methods must be run in main thread (not thread-safe). */ class FGNasalModelData : public SGReferenced @@ -151,6 +153,11 @@ public: // when done. int gcSave(naRef r); void gcRelease(int key); + + /// retrive the associated log object, for displaying log + /// output somewhere (a UI, presumably) + simgear::BufferedLogCallback* log() const + { return _log; } private: friend class FGNasalScript; friend class FGNasalListener; @@ -195,7 +202,9 @@ private: naRef _gcHash; int _callCount; - public: void handleTimer(NasalTimer* t); + simgear::BufferedLogCallback* _log; +public: + void handleTimer(NasalTimer* t); };