|
|
@@ -1,10 +1,11 @@
|
|
|
-#include<iostream>
|
|
|
+#include <algorithm>
|
|
|
+#include <iostream>
|
|
|
+#include <utility>
|
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
#include <unistd.h>
|
|
|
#include <signal.h>
|
|
|
#include <string.h>
|
|
|
-#include <utility>
|
|
|
|
|
|
#include "curseOutput.hh"
|
|
|
#include "jsonObject.hh"
|
|
|
@@ -70,18 +71,21 @@ static void _resizeFnc(int signo)
|
|
|
runningInst->onsig(signo);
|
|
|
}
|
|
|
|
|
|
-void CurseOutput::redraw()
|
|
|
+bool CurseOutput::redraw()
|
|
|
{
|
|
|
std::pair<int, int> screenSize;
|
|
|
std::pair<int, int> cursor;
|
|
|
+ bool result;
|
|
|
|
|
|
select_up = select_down = select_parent = nullptr;
|
|
|
- selectFound = false;
|
|
|
+ selectFound = selectIsLast = selectIsFirst = false;
|
|
|
getScreenSize(screenSize, cursor);
|
|
|
- cursor.first += topleft.second->getLevel() * indentLevel;
|
|
|
+ cursor.first = 0;
|
|
|
+ cursor.second = 0;
|
|
|
clear();
|
|
|
- redraw(cursor, screenSize, topleft.second, dynamic_cast<const JSonContainer *> (topleft.second));
|
|
|
- move(screenSize.second, screenSize.first);
|
|
|
+ result = redraw(cursor, screenSize, data, dynamic_cast<const JSonContainer *> (data));
|
|
|
+ if (!result && !select_down)
|
|
|
+ selectIsLast = true;
|
|
|
if (!select_down)
|
|
|
select_down = selection;
|
|
|
if (!select_up)
|
|
|
@@ -89,61 +93,14 @@ void CurseOutput::redraw()
|
|
|
if (!select_parent)
|
|
|
select_parent = selection;
|
|
|
refresh();
|
|
|
-}
|
|
|
-
|
|
|
-void CurseOutput::getScreenSize(std::pair<int, int> &ss, std::pair<int, int> &bs)
|
|
|
-{
|
|
|
- getmaxyx(stdscr, ss.second, ss.first);
|
|
|
- getbegyx(stdscr, bs.second, bs.first);
|
|
|
-}
|
|
|
-
|
|
|
-CurseOutput::t_nextKey CurseOutput::findNext(const JSonElement *item)
|
|
|
-{
|
|
|
- const JSonContainer *parent = item->getParent();
|
|
|
- if (parent == nullptr)
|
|
|
- return t_nextKey::empty(); // Root node, can't have brothers
|
|
|
- if (dynamic_cast<const JSonObject *>(parent) != nullptr)
|
|
|
- {
|
|
|
- const JSonObject *oParent = (const JSonObject *) parent;
|
|
|
- JSonObject::const_iterator it = oParent->cbegin();
|
|
|
- while (it != oParent->cend())
|
|
|
- {
|
|
|
- if ((*it).second == item)
|
|
|
- {
|
|
|
- it++;
|
|
|
- if (it == oParent->cend())
|
|
|
- return t_nextKey::empty(); // Last item
|
|
|
- return t_nextKey(std::pair<Optional<const std::string>, const JSonElement *>((*it).first, (*it).second));
|
|
|
- }
|
|
|
- it++;
|
|
|
- }
|
|
|
- return t_nextKey::empty();
|
|
|
- }
|
|
|
- if (dynamic_cast<const JSonArray *>(parent) != nullptr)
|
|
|
- {
|
|
|
- const JSonArray *aParent = (const JSonArray *) parent;
|
|
|
- JSonArray::const_iterator it = aParent->cbegin();
|
|
|
- while (it != aParent->cend())
|
|
|
- {
|
|
|
- if (*it == item)
|
|
|
- {
|
|
|
- it++;
|
|
|
- if (it == aParent->cend())
|
|
|
- return t_nextKey::empty(); // Last item
|
|
|
- return t_nextKey(std::pair<Optional<const std::string>, const JSonElement *>(Optional<const std::string>::empty(), *it));
|
|
|
- }
|
|
|
- it++;
|
|
|
- }
|
|
|
- return t_nextKey::empty();
|
|
|
- }
|
|
|
- return t_nextKey::empty(); // Primitive, can't have child (impossible)
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<int, int> &maxSize, const JSonElement *item, const JSonContainer *parent)
|
|
|
{
|
|
|
do
|
|
|
{
|
|
|
- checkSelection(item, parent);
|
|
|
+ checkSelection(item, parent, cursor);
|
|
|
if (dynamic_cast<const JSonContainer*>(item))
|
|
|
{
|
|
|
if (!writeContainer(cursor, maxSize, (const JSonContainer *) item))
|
|
|
@@ -152,7 +109,7 @@ bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<int, int>
|
|
|
else
|
|
|
{
|
|
|
write(cursor.first, cursor.second, item, selection == item);
|
|
|
- if (++cursor.second > maxSize.second)
|
|
|
+ if (++cursor.second - topleft> maxSize.second -1)
|
|
|
return false;
|
|
|
}
|
|
|
t_nextKey next = findNext(item);
|
|
|
@@ -166,19 +123,6 @@ bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<int, int>
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-void CurseOutput::checkSelection(const JSonElement *item, const JSonElement *parent)
|
|
|
-{
|
|
|
- if (selection == item)
|
|
|
- {
|
|
|
- select_parent = parent;
|
|
|
- selectFound = true;
|
|
|
- }
|
|
|
- else if (!selectFound)
|
|
|
- select_up = item;
|
|
|
- else if (!select_down)
|
|
|
- select_down = item;
|
|
|
-}
|
|
|
-
|
|
|
bool CurseOutput::writeContainer(std::pair<int, int> &cursor, const std::pair<int, int> &maxSize, const JSonContainer *item)
|
|
|
{
|
|
|
char childDelimiter[2];
|
|
|
@@ -195,21 +139,26 @@ bool CurseOutput::writeContainer(std::pair<int, int> &cursor, const std::pair<in
|
|
|
std::string ss;
|
|
|
ss.append(&childDelimiter[0], 1).append(" ... ").append(&childDelimiter[1], 1);
|
|
|
write(cursor.first, cursor.second, ss, selection == item);
|
|
|
- cursor.first -= indentLevel /2;
|
|
|
- return !(++cursor.second > maxSize.second);
|
|
|
}
|
|
|
-
|
|
|
- write(cursor.first, cursor.second, childDelimiter[0], selection == item);
|
|
|
- if (++cursor.second > maxSize.second)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (isObject)
|
|
|
- writeContent(cursor, maxSize, (const JSonObject *)item);
|
|
|
else
|
|
|
- writeContent(cursor, maxSize, (const JSonArray *)item);
|
|
|
- write(cursor.first, cursor.second, childDelimiter[1], selection == item);
|
|
|
+ {
|
|
|
+ write(cursor.first, cursor.second, childDelimiter[0], selection == item);
|
|
|
+ if (++cursor.second - topleft > maxSize.second -1)
|
|
|
+ return false;
|
|
|
+ if (isObject)
|
|
|
+ {
|
|
|
+ if (!writeContent(cursor, maxSize, (const JSonObject *)item))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (!writeContent(cursor, maxSize, (const JSonArray *)item))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ write(cursor.first, cursor.second, childDelimiter[1], selection == item);
|
|
|
+ }
|
|
|
cursor.first -= indentLevel /2;
|
|
|
- return !(++cursor.second > maxSize.second);
|
|
|
+ return (++cursor.second - topleft <= maxSize.second -1);
|
|
|
}
|
|
|
|
|
|
bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<int, int> &maxSize, const JSonArray *item)
|
|
|
@@ -231,10 +180,10 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<int,
|
|
|
if (dynamic_cast<const JSonContainer *>(ipair.second) == nullptr
|
|
|
|| ((const JSonContainer *) ipair.second)->size() == 0)
|
|
|
{
|
|
|
- checkSelection(ipair.second, item);
|
|
|
+ checkSelection(ipair.second, item, cursor);
|
|
|
write(cursor.first, cursor.second, ipair.first +": " +ipair.second->stringify(), selection == ipair.second);
|
|
|
cursor.first -= indentLevel /2;
|
|
|
- if (++cursor.second > maxSize.second)
|
|
|
+ if (++cursor.second - topleft > maxSize.second -1)
|
|
|
return false;
|
|
|
}
|
|
|
else if (collapsed.find((const JSonContainer *)ipair.second) != collapsed.end())
|
|
|
@@ -246,10 +195,10 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<int,
|
|
|
memcpy(childDelimiter, "[]", sizeof(*childDelimiter) * 2);
|
|
|
std::string ss = ipair.first;
|
|
|
ss.append(": ").append(&childDelimiter[0], 1).append(" ... ").append(&childDelimiter[1], 1);
|
|
|
- checkSelection(ipair.second, item);
|
|
|
+ checkSelection(ipair.second, item, cursor);
|
|
|
write(cursor.first, cursor.second, ss, selection == ipair.second);
|
|
|
cursor.first -= indentLevel /2;
|
|
|
- if (++cursor.second > maxSize.second)
|
|
|
+ if (++cursor.second - topleft > maxSize.second -1)
|
|
|
return false;
|
|
|
}
|
|
|
else
|
|
|
@@ -269,7 +218,7 @@ bool CurseOutput::writeKey(const std::string &key, std::pair<int, int> &cursor,
|
|
|
{
|
|
|
write(cursor.first, cursor.second, key +": ", selected);
|
|
|
cursor.first += indentLevel;
|
|
|
- return !(++cursor.second > maxSize);
|
|
|
+ return (++cursor.second - topleft <= maxSize -1);
|
|
|
}
|
|
|
|
|
|
void CurseOutput::write(const int &x, const int &y, const JSonElement *item, bool selected)
|
|
|
@@ -279,26 +228,32 @@ void CurseOutput::write(const int &x, const int &y, const JSonElement *item, boo
|
|
|
|
|
|
void CurseOutput::write(const int &x, const int &y, const char item, bool selected)
|
|
|
{
|
|
|
+ int offsetY = y - topleft;
|
|
|
+ if (offsetY < 0)
|
|
|
+ return;
|
|
|
if (selected)
|
|
|
{
|
|
|
attron(A_REVERSE | A_BOLD);
|
|
|
- mvprintw(y, x, "%c", item);
|
|
|
+ mvprintw(offsetY, x, "%c", item);
|
|
|
attroff(A_REVERSE | A_BOLD);
|
|
|
}
|
|
|
else
|
|
|
- mvprintw(y, x, "%c", item);
|
|
|
+ mvprintw(offsetY, x, "%c", item);
|
|
|
}
|
|
|
|
|
|
void CurseOutput::write(const int &x, const int &y, const char *str, bool selected)
|
|
|
{
|
|
|
+ int offsetY = y - topleft;
|
|
|
+ if (offsetY < 0)
|
|
|
+ return;
|
|
|
if (selected)
|
|
|
{
|
|
|
attron(A_REVERSE | A_BOLD);
|
|
|
- mvprintw(y, x, "%s", str);
|
|
|
+ mvprintw(offsetY, x, "%s", str);
|
|
|
attroff(A_REVERSE | A_BOLD);
|
|
|
}
|
|
|
else
|
|
|
- mvprintw(y, x, "%s", str);
|
|
|
+ mvprintw(offsetY, x, "%s", str);
|
|
|
}
|
|
|
|
|
|
void CurseOutput::write(const int &x, const int &y, const std::string &str, bool selected)
|
|
|
@@ -306,6 +261,69 @@ void CurseOutput::write(const int &x, const int &y, const std::string &str, bool
|
|
|
write(x, y, str.c_str(), selected);
|
|
|
}
|
|
|
|
|
|
+void CurseOutput::getScreenSize(std::pair<int, int> &ss, std::pair<int, int> &bs)
|
|
|
+{
|
|
|
+ getmaxyx(stdscr, ss.second, ss.first);
|
|
|
+ getbegyx(stdscr, bs.second, bs.first);
|
|
|
+}
|
|
|
+
|
|
|
+CurseOutput::t_nextKey CurseOutput::findNext(const JSonElement *item)
|
|
|
+{
|
|
|
+ const JSonContainer *parent = item->getParent();
|
|
|
+ if (parent == nullptr)
|
|
|
+ return t_nextKey::empty(); // Root node, can't have brothers
|
|
|
+ if (dynamic_cast<const JSonObject *>(parent) != nullptr)
|
|
|
+ {
|
|
|
+ const JSonObject *oParent = (const JSonObject *) parent;
|
|
|
+ JSonObject::const_iterator it = oParent->cbegin();
|
|
|
+ while (it != oParent->cend())
|
|
|
+ {
|
|
|
+ if ((*it).second == item)
|
|
|
+ {
|
|
|
+ it++;
|
|
|
+ if (it == oParent->cend())
|
|
|
+ return t_nextKey::empty(); // Last item
|
|
|
+ return t_nextKey(std::pair<Optional<const std::string>, const JSonElement *>((*it).first, (*it).second));
|
|
|
+ }
|
|
|
+ it++;
|
|
|
+ }
|
|
|
+ return t_nextKey::empty();
|
|
|
+ }
|
|
|
+ if (dynamic_cast<const JSonArray *>(parent) != nullptr)
|
|
|
+ {
|
|
|
+ const JSonArray *aParent = (const JSonArray *) parent;
|
|
|
+ JSonArray::const_iterator it = aParent->cbegin();
|
|
|
+ while (it != aParent->cend())
|
|
|
+ {
|
|
|
+ if (*it == item)
|
|
|
+ {
|
|
|
+ it++;
|
|
|
+ if (it == aParent->cend())
|
|
|
+ return t_nextKey::empty(); // Last item
|
|
|
+ return t_nextKey(std::pair<Optional<const std::string>, const JSonElement *>(Optional<const std::string>::empty(), *it));
|
|
|
+ }
|
|
|
+ it++;
|
|
|
+ }
|
|
|
+ return t_nextKey::empty();
|
|
|
+ }
|
|
|
+ return t_nextKey::empty(); // Primitive, can't have child (impossible)
|
|
|
+}
|
|
|
+
|
|
|
+void CurseOutput::checkSelection(const JSonElement *item, const JSonElement *parent, const std::pair<int, int> &cursor)
|
|
|
+{
|
|
|
+ if (selection == item)
|
|
|
+ {
|
|
|
+ if (cursor.second <= topleft)
|
|
|
+ selectIsFirst = true;
|
|
|
+ select_parent = parent;
|
|
|
+ selectFound = true;
|
|
|
+ }
|
|
|
+ else if (!selectFound)
|
|
|
+ select_up = item;
|
|
|
+ else if (!select_down)
|
|
|
+ select_down = item;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Read input and expect signal
|
|
|
* @Return true on:
|
|
|
@@ -330,13 +348,19 @@ bool CurseOutput::readInput()
|
|
|
case KEY_UP:
|
|
|
case 'K':
|
|
|
case 'k':
|
|
|
- selection = select_up;
|
|
|
+ if (selectIsFirst && topleft)
|
|
|
+ topleft = std::max(topleft -3, 0);
|
|
|
+ else
|
|
|
+ selection = select_up;
|
|
|
return true;
|
|
|
|
|
|
case KEY_DOWN:
|
|
|
case 'j':
|
|
|
case 'J':
|
|
|
- selection = select_down;
|
|
|
+ if (selectIsLast)
|
|
|
+ topleft += 2;
|
|
|
+ else
|
|
|
+ selection = select_down;
|
|
|
return true;
|
|
|
|
|
|
case 'l':
|
|
|
@@ -396,8 +420,7 @@ void CurseOutput::init()
|
|
|
signal(SIGINT, _resizeFnc);
|
|
|
signal(SIGTERM, _resizeFnc);
|
|
|
signal(SIGKILL, _resizeFnc);
|
|
|
- topleft.first = std::pair<unsigned int, unsigned int>(0, 0);
|
|
|
- topleft.second = data;
|
|
|
+ topleft = 0;
|
|
|
}
|
|
|
|
|
|
void CurseOutput::shutdown()
|