Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
error-log-display.hpp
Go to the documentation of this file.
1/*
2 ERROR-LOG-DISPLAY.hpp - display of error messages in a text box
3
4 Copyright (C)
5 2017, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
50#ifndef STAGE_WIDGET_ERROR_LOG_DISPLAY_H
51#define STAGE_WIDGET_ERROR_LOG_DISPLAY_H
52
53#include "stage/gtk-base.hpp"
58#include "lib/format-string.hpp"
59#include "lib/symbol.hpp"
60#include "lib/util.hpp"
61
62#include <utility>
63#include <vector>
64
65
66
67namespace stage {
68namespace widget {
69
70 using util::max;
71 using util::_Fmt;
72 using lib::Literal;
73 using std::make_pair;
74 using std::vector;
75 using std::move;
76
77 namespace {
78
79 using Tag = Glib::RefPtr<Gtk::TextBuffer::Tag>;
80
86 inline void
87 populateStandardTextTags (Glib::RefPtr<Gtk::TextBuffer::TagTable> tagTable)
88 {
89 Tag errorTag = Gtk::TextBuffer::Tag::create (cuString{TAG_ERROR});
90 errorTag->property_background() = "Yellow";
91 errorTag->property_weight() = PANGO_WEIGHT_BOLD;
92 tagTable->add (errorTag);
93
94 Tag warnTag = Gtk::TextBuffer::Tag::create (cuString{TAG_WARN});
95 warnTag->property_background() = "LightYellow";
96 tagTable->add (warnTag);
97 }
98 }
99
100
101
102 /*********************************************************************/
115 : public Gtk::ScrolledWindow
116 {
117
118 using Mark = Glib::RefPtr<Gtk::TextBuffer::Mark>;
119 using Entry = std::pair<Mark,Mark>;
121
122 using SignalErrorChanged = sigc::signal<void, bool>;
123
124 vector<Entry> errorMarks_;
126
128
129
130 public:
132
134 : Gtk::ScrolledWindow()
135 , errorMarks_{}
136 , textLog_{}
137 {
138 set_size_request (200, 80); // must be > 50 for the scrollbar to work properly
139 property_expand() = true; // always grab any available additional space
140 set_border_width (10);
141 set_shadow_type (Gtk::SHADOW_NONE);
142
143 // the vertical scrollbar will always be necessary....
144 set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
145 textLog_.set_editable (false);
146 this->add (textLog_);
147
148 populateStandardTextTags (textLog_.get_buffer()->get_tag_table());
149 }
150
153
154
156 void
158 {
159 bool shallNotify = this->isError();
160
161 errorMarks_.clear();
162 size_t lineCnt = max (0, textLog_.get_buffer()->get_line_count() - 1);
163 string placeholder;
164 if (lineCnt > 0)
165 placeholder = _Fmt{_("───════ %d preceding lines removed ════───\n")} % lineCnt;
166 textLog_.get_buffer()->set_text (placeholder); // discard existing content
167
168 if (shallNotify)
169 errorChangedSignal_.emit (false);
170 }
171
172
175 void
176 addInfo (string text)
177 {
178 addEntry (text);
179 }
180
182 void
183 addWarn (string text)
184 {
185 addEntry ("WARNING: "+text, TAG_WARN);
186 }
187
195 void
196 addError (string text)
197 {
198 bool shallNotify = not this->isError();
199
200 errorMarks_.emplace_back(
201 addEntry ("ERROR: "+text, TAG_ERROR));
202 if (not expand.isExpanded())
203 expand (true);
204
205 if (shallNotify)
206 errorChangedSignal_.emit (true);
207 }
208
214 void
216 {
217 auto newBuff = Gtk::TextBuffer::create (textLog_.get_buffer()->get_tag_table());
218 vector<Entry> newMarks;
219 for (Entry& entry : errorMarks_)
220 {
221 newBuff->insert (newBuff->end(), "\n");
222 auto pos = newBuff->end();
223 --pos;
224 newMarks.emplace_back(
225 make_pair (
226 newBuff->create_mark (pos, true), // "left gravity" : stays to the left of inserted text
227 newBuff->create_mark (pos, false))); // "right gravity": sticks right behind the inserted text))
228
229 newBuff->insert (pos // copy from old to new buffer, complete with formatting tag
230 ,entry.first->get_iter()
231 ,entry.second->get_iter()
232 );
233 }
234 // install the reduced new buffer
235 auto oldBuff = textLog_.get_buffer();
236 textLog_.set_buffer(newBuff);
237 swap (errorMarks_, newMarks);
238
239 // add a marker line to indicate the removed old log contents
240 int oldLines = oldBuff->get_line_count();
241 int newLines = newBuff->get_line_count();
242 ASSERT (oldLines >= newLines);
243 addInfo (_Fmt{_("───════ %d old log lines removed ════───\n")} % (oldLines-newLines));
244 }
245
246
248 void
250 {
251 if (not isError()) return;
252
253 auto buff = textLog_.get_buffer();
254 for (Entry& entry : errorMarks_)
255 {
256 auto begin = entry.first->get_iter();
257 auto end = entry.second->get_iter();
258
259 buff->remove_tag_by_name(uString{TAG_ERROR}, begin,end);
260 buff->apply_tag_by_name (uString{TAG_WARN}, begin,end);
261 }
262 errorMarks_.clear();
263 errorChangedSignal_.emit (false);
264 }
265
266
271 void
273 {
274 textLog_.flash();
275 }
276
277
278 /* ======= Error-State ======= */
279
280 bool
281 isError() const
282 {
283 return not errorMarks_.empty();
284 }
285
289 {
290 return errorChangedSignal_;
291 }
292
293
294
295 private:/* ===== Internals ===== */
296
310 Entry
311 addEntry (string const& text, Literal markupTagName =nullptr)
312 {
313 auto buff = textLog_.get_buffer();
314 buff->insert (buff->end(), "\n");
315 auto pos = buff->end();
316 --pos;
317 auto begin = buff->create_mark (pos, true); // "left gravity" : stays to the left of inserted text
318 auto after = buff->create_mark (pos, false); // "right gravity": sticks right behind the inserted text
319 if (markupTagName)
320 buff->insert_with_tag(pos, text, cuString{markupTagName});
321 else
322 buff->insert (pos, text);
323 textLog_.scroll_to (begin);
324 return make_pair (move(begin), move(after));
325 }
326 };
327
328
329}}// namespace stage::widget
330#endif /*STAGE_WIDGET_ERROR_LOG_DISPLAY_H*/
Inline string literal.
Definition symbol.hpp:78
Functor component to support the default implementation of expanding/collapsing.
Functor component to support the default implementation of revealing an UI-Element.
Widget to display log and error messages.
void clearInfoMsg()
clear all mere information messages; retain just the previously tagged errors
void turnError_into_InfoMsg()
visit all errors and downgrade the markup; discard all bookmarks
void addError(string text)
present an error notification prominently.
void triggerFlash()
temporarily change display style to prompt for attention; set callback-timeout for return to normal s...
Entry addEntry(string const &text, Literal markupTagName=nullptr)
add message entry to the (ever growing) text buffer.
void clearAll()
empty text buffer and discard all error bookmarks
sigc::signal< void, bool > SignalErrorChanged
Glib::RefPtr< Gtk::TextBuffer::Mark > Mark
SignalErrorChanged signalErrorChanged()
signal fired when error state changes
void addWarn(string text)
add an information message, formatted more prominent as warning
void addInfo(string text)
just add normal information message to buffer, without special markup and without expanding the widge...
A front-end for using printf-style formatting.
Helper components to implement some standard UI-element actions by installing a functor.
Decorator to add the ability to display a visual flash action to a GTK widget.
Front-end for printf-style string template interpolation.
A set of basic GTK includes for the UI.
#define _(String)
Definition gtk-base.hpp:68
Major public Interface of the Lumiera GUI.
void populateStandardTextTags(Glib::RefPtr< Gtk::TextBuffer::TagTable > tagTable)
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
const uString cuString
Definition gtk-base.hpp:93
const Literal TAG_ERROR
const Literal TAG_WARN
Glib::ustring uString
Definition gtk-base.hpp:92
auto max(IT &&elms)
Definition of access keys for uniform UI styling.
Marker types to indicate a literal string and a Symbol.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...