OnixS C++ ICE Binary Order Entry Handler 1.1.1
API Documentation
Loading...
Searching...
No Matches
CUI.h
Go to the documentation of this file.
1/*
2* Copyright Onix Solutions Limited [OnixS]. All rights reserved.
3*
4* This software owned by Onix Solutions Limited [OnixS] and is protected by copyright law
5* and international copyright treaties.
6*
7* Access to and use of the software is governed by the terms of the applicable OnixS Software
8* Services Agreement (the Agreement) and Customer end user license agreements granting
9* a non-assignable, non-transferable and non-exclusive license to use the software
10* for it's own data processing purposes under the terms defined in the Agreement.
11*
12* Except as otherwise granted within the terms of the Agreement, copying or reproduction of any part
13* of this source code or associated reference material to any other location for further reproduction
14* or redistribution, and any amendments to this copyright notice, are expressly prohibited.
15*
16* Any reproduction or redistribution for sale or hiring of the Software not in accordance with
17* the terms of the Agreement is a violation of copyright law.
18*/
19#pragma once
20
24
25#include "Book.h"
26#include "Utils.h"
27
28#include <sstream>
29#include <iostream>
30#include <string>
31#include <vector>
32#include <thread>
33#include <chrono>
34#include <iomanip>
35
36#ifdef _WIN32
37#include <windows.h>
38#endif
39
40namespace CUI {
41
42using namespace ONIXS_ICEBOE_NAMESPACE;
44
46struct Screen
47{
48 static void init()
49 {
50#ifdef _WIN32
51 vtMode() = enableVtMode();
52#endif
53 }
54
55 struct DeleteLast {size_t n;};
56 inline static DeleteLast deleteLast(size_t n) {return {n};}
57
58 inline friend std::ostream& operator<<(std::ostream& os, const DeleteLast& m)
59 {
60 if(vtMode()) os << "\x1b[" << m.n << "F" << "\x1b[" << m.n << "M" << std::flush;
61 return os;
62 }
63
64 static std::ostream& reset(std::ostream& os)
65 {
66 if(vtMode()) os << "\x1b[0m";
67 return os;
68 }
69
70 static std::ostream& bold(std::ostream& os)
71 {
72 if(vtMode()) os << "\x1b[1m";
73 return os;
74 }
75
76 static std::ostream& red(std::ostream& os)
77 {
78 if(vtMode()) os << "\x1b[38;2;255;64;64m";
79 return os;
80 }
81
82 static std::ostream& green(std::ostream& os)
83 {
84 if(vtMode()) os << "\x1b[38;2;0;255;64m";
85 return os;
86 }
87
88 static std::ostream& yellow(std::ostream& os)
89 {
90 if(vtMode()) os << "\x1b[38;2;255;255;64m";
91 return os;
92 }
93
94 static std::ostream& black(std::ostream& os)
95 {
96 if(vtMode()) os << "\x1b[30m";
97 return os;
98 }
99
100 static std::ostream& onRed (std::ostream& os)
101 {
102 if(vtMode()) os << "\x1b[48;2;210;120;120m";
103 return os;
104 }
105
106 static std::ostream& onGreen (std::ostream& os)
107 {
108 if(vtMode()) os << "\x1b[48;2;120;200;150m";
109 return os;
110 }
111
112 static std::ostream& onYellow(std::ostream& os)
113 {
114 if(vtMode()) os << "\x1b[48;2;235;220;160m";
115 return os;
116 }
117
118 static std::ostream& onCyan (std::ostream& os)
119 {
120 if(vtMode()) os << "\x1b[48;2;150;210;220m";
121 return os;
122 }
123
124 static std::ostream& onWhite (std::ostream& os)
125 {
126 if(vtMode()) os << "\x1b[48;2;240;240;240m";
127 return os;
128 }
129
130 static std::ostream& out()
131 {
132 return std::cout;
133 }
134
135 template<typename T>
136 static T getInput(const T& defaultValue = {})
137 {
138 std::string userInput;
139 std::getline(std::cin, userInput);
140
141 if (userInput.empty())
142 return defaultValue;
143
144 return Samples::parseUserInput<T>(userInput);
145 }
146
147 template<typename... Args>
148 static void info(const Args&... args)
149 {
150 Guard g(mutex(), out());
151 out() << "\n" << bold << black << onGreen << "[INFO]" << reset << " " << append(args...) << "\n";
152 }
153
154 template<typename... Args>
155 static void error(const Args&... args)
156 {
157 Guard g(mutex(), out());
158 out() << "\n" << bold << black << onRed << "[ERROR]" << reset << " " << append(args...) << "\n";
159 }
160
161 template<typename... Args>
162 static void warning(const Args&... args)
163 {
164 Guard g(mutex(), out());
165 out() << "\n" << bold << black << onYellow << "[WARN]" << reset << " " << append(args...) << "\n";
166 }
167
168 template<typename... Args>
169 static void trace(const Args&... args)
170 {
171 Guard g(mutex(), out());
172 out() << "\n" << bold << black << onCyan << "[TRACE]" << reset << " " << append(args...) << "\n";
173 }
174
175 template<typename... Args>
176 static void out(const Args&... args)
177 {
178 Guard g(mutex(), out());
179 out() << append(args...) << std::endl;
180 }
181
182 static void printProgress(size_t cur, size_t total)
183 {
184 Guard g(mutex(), out());
185
186 const size_t width = 40;
187
188 if (total == 0) total = 1;
189 cur = (std::min)(cur, total);
190
191 const double r = double(cur) / double(total);
192 const auto filled = static_cast<std::size_t>(r * width);
193
194 out() << '\r' << '[' << std::string(filled, '#') << std::string(width - filled, ' ')
195 << "] " << std::setw(3) << int(r * 100) << '%' << std::flush;
196
197 if (cur == total) out() << '\n';
198 }
199
200 enum class Direction {In, Out};
201
202 static std::string toStr(Direction direction)
203 {
204#ifdef _WIN32
205 return direction == Direction::In ? "[<-]" : "[->]";
206#else
207 return direction == Direction::In ? "[←]" : "[→]";
208#endif
209 }
210
211 static void traceMsg(const std::string& sessionId, SbeMessage message, Direction direction)
212 {
213 Guard g(mutex(), out());
214
215 out() << "\n" << bold << black << onCyan << toStr(direction) << reset << " ";
216
217 out() << "[" << sessionId << "] ";
218
219 const auto printMsg = [&](const auto msg)
220 {
221 out() << msg.toString();
222
223 const auto text = formatMsg(msg);
224
225 if(!text.empty())
226 out() << "\n\t" << text;
227 };
228
229 if (!ONIXS_ICEBOE_MESSAGING_NAMESPACE::processTypified(message, printMsg))
230 out() << yellow << "Unknown message type [" << message.templateId() << "]" << reset;
231
232 out() << "\n";
233 }
234
235 template <typename ItemType>
236 static void outItems(const ItemType & items)
237 {
238 Guard g(mutex(), out());
239
240 for (size_t index = 0; index < items.size(); ++index)
241 out() << "\t" << bold << black << onGreen << "[" << (index + 1) << "]" << reset << " " << items[index].text_ << "\n";
242 }
243
244 template <typename ItemType>
245 static void outList(const ItemType & list)
246 {
247 Guard g(mutex(), out());
248
249 out() << "\t[";
250
251 bool first = true;
252 for (const auto& item : list)
253 {
254 if (!first)
255 out() << ",";
256
257 first = false;
258 out() << item;
259 }
260
261 out() << "]\n";
262 }
263
264 static std::chrono::milliseconds sinceLstUpdate()
265 {
266 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - lastUpdateTime());
267 }
268
269private:
270 template<typename T>
271 static void appendToStream(std::ostringstream& oss, const T& value)
272 {
273 oss << value;
274 }
275
276 template<typename T, typename... Args>
277 static void appendToStream(std::ostringstream& oss, const T& value, const Args&... args)
278 {
279 oss << value;
280 appendToStream(oss, args...);
281 }
282
283 template <typename... Args>
284 static auto append(const Args&... args)
285 {
286 std::ostringstream oss;
287 appendToStream(oss, args...);
288 return oss.str();
289 }
290
291#ifdef _WIN32
293 static bool enableVtMode()
294 {
295 const HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
296 if (h == INVALID_HANDLE_VALUE)
297 return false;
298
299 DWORD mode = 0;
300 if (!GetConsoleMode(h, &mode))
301 return false;
302
303 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
304
305 return SetConsoleMode(h, mode) != 0;
306 }
307#endif
308 static bool& vtMode()
309 {
310 static bool value = true;
311 return value;
312 }
313
314 using Mutex = std::recursive_mutex;
315
316 struct Guard : public std::lock_guard<Mutex>
317 {
318 Guard(Mutex& mutex, std::ostream& s)
319 : std::lock_guard<Mutex>(mutex)
320 , s_(s)
321 {}
322
323 ~Guard()
324 {
325 try { s_ << reset << std::flush; } catch(...){}
326 setLastUpdateTime();
327 }
328
329 std::ostream& s_;
330 };
331
332 static Mutex& mutex()
333 {
334 static Mutex mutex;
335 return mutex;
336 }
337
338 static std::chrono::time_point<std::chrono::steady_clock>& lastUpdateTime()
339 {
340 static auto lastUpdateTime = std::chrono::steady_clock::now();
341 return lastUpdateTime;
342 }
343
344 static void setLastUpdateTime()
345 {
346 lastUpdateTime() = std::chrono::steady_clock::now();
347 }
348};
349
350using Command = std::function<void()>;
351
354{
355 MenuItem(const std::string& text, const std::string& commandText, const std::initializer_list<Command>& items)
356 : text_(text)
357 , commandText_(commandText)
358 , commands_{items}
359 {}
360
361 MenuItem(const std::string& text, const std::string& commandText, const Command& command)
362 : text_(text)
363 , commandText_(commandText)
364 , commands_{command}
365 {}
366
367 std::string text_;
368 std::string commandText_;
369
370 std::vector<Command> commands_;
371};
372
374class Menu
375{
376public:
377 Menu(const std::initializer_list<MenuItem>& items)
378 : items_{items}
379 {
380 Screen::init();
381 outputItems();
382 }
383
385 void processRequests() const
386 {
387 while (!stopRequested_)
388 processRequest();
389 }
390
393 void outputItems() const
394 {
395 Screen::info("Commands:");
396 Screen::outItems(items_);
397 }
398
400 void stopRequest() noexcept
401 {
402 stopRequested_ = true;
403 }
404
405private:
406 bool stopRequested_ = false;
407
409 std::vector<MenuItem> items_;
410
412 void processRequest() const
413 {
414 static const auto CommandExecutionTimeout = std::chrono::milliseconds(500);
415
416 if(Screen::sinceLstUpdate() < CommandExecutionTimeout)
417 return;
418
419 Screen::info("Select operation to perform. Enter a choice (1 - Show options):");
420
421 size_t selectedItemNumber = 0;
422 while (true)
423 {
424 try
425 {
426 const auto userInput = Screen::getInput<size_t>();
428 selectedItemNumber = userInput - 1;
429 }
430 catch(...)
431 {
432 continue;
433 }
434
435 if(selectedItemNumber < items_.size())
436 break;
437
438 Screen::warning("Invalid command requested. Repeat a choice (1 - Show options):");
439 }
440
441 try
442 {
443 const auto& selectedItem = items_[selectedItemNumber];
444
445 Screen::info(selectedItem.commandText_ + "...");
446
447 const auto commands = selectedItem.commands_;
448 for(auto command : commands)
449 {
450 command();
451
452 if(stopRequested_)
453 return;
454
457 std::this_thread::sleep_for(CommandExecutionTimeout);
458 }
459 }
460 catch (const std::exception& ex)
461 {
462 Screen::error(ex.what());
463 }
464 }
465
466friend struct ListViewer;
467};
468
470{
472 template <typename EntryList, typename Print>
473 static void outputItems(const EntryList& items, Print print = [](auto item){ return toStr(item);}, size_t itemsPerPage = 100)
474 {
475 if (items.empty())
476 {
477 Screen::info("[]");
478 return;
479 }
480
481 size_t itemsToOutput = itemsPerPage;
482
483 std::size_t n = 0;
484 for (const auto& item : items)
485 {
486 if (0 == --itemsToOutput)
487 {
488 itemsToOutput = itemsPerPage;
489
490 if (!shouldContinue())
491 return;
492 }
493
494 Screen::out() << "\n"
495 << Screen::bold << Screen::black << Screen::onCyan << "[" << std::to_string(++n) << "]"
496 << Screen::reset << " " << print(item) << "\n";
497 }
498 }
499
500private:
501 static bool shouldContinue()
502 {
503 Screen::info("Press <Enter> to view next page or Enter 'q' to abort current action: ");
504 const auto userInput = Screen::getInput<std::string>();
505
506 return userInput.empty();
507 }
508};
509
510}
#define ONIXS_ICEBOE_NAMESPACE
Definition ABI.h:113
#define ONIXS_ICEBOE_MESSAGING_NAMESPACE
Definition ABI.h:114
void stopRequest() noexcept
Requests stop.
Definition CUI.h:400
Menu(const std::initializer_list< MenuItem > &items)
Definition CUI.h:377
friend struct ListViewer
Definition CUI.h:466
void outputItems() const
Outputs items' names onto the screen.
Definition CUI.h:393
void processRequests() const
Processes user requests until any command terminates the execution.
Definition CUI.h:385
MessageTemplateId templateId() const noexcept
Definition CUI.h:40
std::function< void()> Command
Definition CUI.h:350
std::string formatMsg(const Message message, typename std::enable_if< isFormattableMsg< Message >::value, void * >::type=nullptr)
Definition Formatting.h:85
std::string toStr(const FixedPointDecimal< Mantissa, Exponent > &)
Serializes a fixed-point decimal into a string.
auto print(OrderPtr order)
Definition Order.h:77
T parseUserInput(const std::string &userInput, typename std::enable_if< std::is_integral< T >::value, void * >::type=nullptr)
Definition Utils.h:142
bool args(const Options &options, const Char *option, Iterator target, size_t minQty=0, size_t maxQty=static_cast< size_t >(-1))
Definition Options.h:345
static void outputItems(const EntryList &items, Print print=[](auto item){ return toStr(item);}, size_t itemsPerPage=100)
Outputs list items.
Definition CUI.h:473
std::vector< Command > commands_
Definition CUI.h:370
MenuItem(const std::string &text, const std::string &commandText, const std::initializer_list< Command > &items)
Definition CUI.h:355
MenuItem(const std::string &text, const std::string &commandText, const Command &command)
Definition CUI.h:361
std::string commandText_
Definition CUI.h:368
std::string text_
Definition CUI.h:367
An utility class for console-based input-output.
Definition CUI.h:47
static void traceMsg(const std::string &sessionId, SbeMessage message, Direction direction)
Definition CUI.h:211
static void error(const Args &... args)
Definition CUI.h:155
static std::ostream & onGreen(std::ostream &os)
Definition CUI.h:106
static std::ostream & yellow(std::ostream &os)
Definition CUI.h:88
static DeleteLast deleteLast(size_t n)
Definition CUI.h:56
static void trace(const Args &... args)
Definition CUI.h:169
static std::ostream & onRed(std::ostream &os)
Definition CUI.h:100
static std::ostream & red(std::ostream &os)
Definition CUI.h:76
static std::ostream & onCyan(std::ostream &os)
Definition CUI.h:118
static std::string toStr(Direction direction)
Definition CUI.h:202
static void printProgress(size_t cur, size_t total)
Definition CUI.h:182
static std::ostream & out()
Definition CUI.h:130
static std::ostream & onWhite(std::ostream &os)
Definition CUI.h:124
static void warning(const Args &... args)
Definition CUI.h:162
static std::ostream & bold(std::ostream &os)
Definition CUI.h:70
static void out(const Args &... args)
Definition CUI.h:176
static std::chrono::milliseconds sinceLstUpdate()
Definition CUI.h:264
static std::ostream & green(std::ostream &os)
Definition CUI.h:82
friend std::ostream & operator<<(std::ostream &os, const DeleteLast &m)
Definition CUI.h:58
static void info(const Args &... args)
Definition CUI.h:148
static void outList(const ItemType &list)
Definition CUI.h:245
static void outItems(const ItemType &items)
Definition CUI.h:236
static T getInput(const T &defaultValue={})
Definition CUI.h:136
static std::ostream & black(std::ostream &os)
Definition CUI.h:94
static std::ostream & onYellow(std::ostream &os)
Definition CUI.h:112
static void init()
Definition CUI.h:48
static std::ostream & reset(std::ostream &os)
Definition CUI.h:64