Sfoglia il codice sorgente

[add] vertical scroll

isundil 9 anni fa
parent
commit
380f25b553
2 ha cambiato i file con 122 aggiunte e 99 eliminazioni
  1. 4 4
      include/curseOutput.hh
  2. 118 95
      src/curseOutput.cpp

+ 4 - 4
include/curseOutput.hh

@@ -27,15 +27,15 @@ class CurseOutput
     protected:
         void init();
         void shutdown();
-        void redraw();
         /**
          * return false if bottom of screen is touched
         **/
+        bool redraw();
         bool redraw(std::pair<int, int> &, const std::pair<int, int>&, const JSonElement *, const JSonContainer *);
         bool readInput();
         void getScreenSize(std::pair<int, int> &, std::pair<int, int> &);
         static CurseOutput::t_nextKey findNext(const JSonElement *);
-        void checkSelection(const JSonElement *item, const JSonElement *parent);
+        void checkSelection(const JSonElement *item, const JSonElement *parent, const std::pair<int, int>&);
         void write(const int &x, const int &y, const JSonElement *item, bool selected =false);
         void write(const int &x, const int &y, const std::string &item, bool selected =false);
         void write(const int &x, const int &y, const char item, bool selected =false);
@@ -51,11 +51,11 @@ class CurseOutput
         SCREEN *screen;
         FILE *screen_fd;
         bool breakLoop;
-        std::pair<std::pair<unsigned int, unsigned int>, const JSonElement *> topleft;
+        int topleft;
         const unsigned int indentLevel;
 
         //FIXME optimize
         const JSonElement *select_up, *select_down, *select_parent;
-        bool selectFound;
+        bool selectFound, selectIsLast, selectIsFirst;
 };
 

+ 118 - 95
src/curseOutput.cpp

@@ -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()