]> git.tdb.fi Git - libs/gltk.git/commitdiff
Implement a grid view mode for List
authorMikko Rasa <tdb@tdb.fi>
Thu, 19 Sep 2019 21:47:43 +0000 (00:47 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 19 Sep 2019 21:47:43 +0000 (00:47 +0300)
source/list.cpp
source/list.h

index a5285832b98994f5f9cc4365d41c28c5b37b1176..de7f857935d57050b3f859e6b70186b57361d0de 100644 (file)
@@ -3,6 +3,7 @@
 #include <msp/gl/matrix.h>
 #include <msp/gl/meshbuilder.h>
 #include <msp/input/keys.h>
+#include <msp/strings/format.h>
 #include "graphic.h"
 #include "list.h"
 #include "part.h"
@@ -39,11 +40,13 @@ void List::init()
        input_type = INPUT_NAVIGATION;
 
        item_factory = 0;
+       view_mode = LIST;
        sel_index = -1;
        focus_index = -1;
        first_row = 0;
        max_scroll = 0;
        view_rows = 5;
+       view_columns = 5;
        items_part = 0;
        ignore_slider_change = false;
        dragging = false;
@@ -71,20 +74,34 @@ void List::autosize_special(const Part &part, Geometry &ageom) const
        {
                const Sides &margin = part.get_margin();
 
-               unsigned max_w = 0;
-               unsigned max_h = 0;
+               unsigned items_w = 0;
+               unsigned items_h = 0;
                for(unsigned i=0; i<items.size(); ++i)
                {
                        Geometry igeom;
                        items[i]->autosize(igeom);
-                       max_w = max(max_w, igeom.w);
-                       max_h = max(max_h, igeom.h);
+                       items_w = max(items_w, igeom.w);
+                       items_h = max(items_h, igeom.h);
                }
 
-               unsigned total_h = max_h*(view_rows==0 ? items.size() : view_rows);
+               if(view_mode==GRID)
+               {
+                       unsigned r = view_rows;
+                       unsigned c = view_columns;
+                       if(r==0 && c==0)
+                               r = sqrt(items.size());
+                       if(r==0)
+                               r = (items.size()+c-1)/c;
+                       if(c==0)
+                               c = (items.size()+r-1)/r;
+                       items_w *= c;
+                       items_h *= r;
+               }
+               else
+                       items_h *= (view_rows==0 ? items.size() : view_rows);
 
-               ageom.w = max(ageom.w, max_w+margin.left+margin.right);
-               ageom.h = max(ageom.h, total_h+margin.top+margin.bottom);
+               ageom.w = max(ageom.w, items_w+margin.left+margin.right);
+               ageom.h = max(ageom.h, items_h+margin.top+margin.bottom);
        }
        else if(part.get_name()=="slider")
                autosize_child(slider, part, ageom);
@@ -137,9 +154,15 @@ List::Item *List::create_item(unsigned index)
        return item;
 }
 
-void List::set_view_size(unsigned r)
+void List::set_view_size(unsigned s)
+{
+       set_view_size(s, s);
+}
+
+void List::set_view_size(unsigned r, unsigned c)
 {
        view_rows = r;
+       view_columns = c;
        signal_autosize_changed.emit();
 }
 
@@ -318,7 +341,7 @@ void List::focus_in()
 
 bool List::navigate(Navigation nav)
 {
-       if((nav==NAV_UP || nav==NAV_DOWN) && !items.empty())
+       if((nav==NAV_UP || nav==NAV_DOWN || ((nav==NAV_LEFT || nav==NAV_RIGHT) && view_mode==GRID)) && !items.empty())
                move_focus(nav, true);
        else if(nav==NAV_ACTIVATE)
                set_selected_index(focus_index);
@@ -335,12 +358,28 @@ void List::on_style_change()
 
 void List::move_focus(Navigation nav, bool select)
 {
-       if(nav==NAV_UP)
+       if(nav==NAV_UP && view_mode==GRID)
+       {
+               unsigned row = item_index_to_row(focus_index);
+               if(row>0)
+                       set_focus_index(rows[row-1].first+focus_index-rows[row].first);
+               else
+                       set_focus_index(0);
+       }
+       else if(nav==NAV_DOWN && view_mode==GRID)
+       {
+               unsigned row = item_index_to_row(focus_index);
+               if(row+1<rows.size())
+                       set_focus_index(rows[row+1].first+focus_index-rows[row].first);
+               else
+                       set_focus_index(items.size()-1);
+       }
+       else if(nav==NAV_UP || (nav==NAV_LEFT && view_mode==GRID))
        {
                if(focus_index>0)
                        set_focus_index(focus_index-1);
        }
-       else if(nav==NAV_DOWN)
+       else if(nav==NAV_DOWN || (nav==NAV_RIGHT && view_mode==GRID))
        {
                if(static_cast<unsigned>(focus_index+1)<items.size())
                        set_focus_index(focus_index+1);
@@ -381,20 +420,25 @@ void List::reposition_items(bool record_rows)
 
        const Sides &margin = items_part->get_margin();
        unsigned view_w = geom.w-min(geom.w, margin.left+margin.right);
+       unsigned x = 0;
        unsigned y = 0;
        unsigned row_h = 0;
        for(unsigned i=0; i<items.size(); ++i)
        {
                const Geometry &igeom = items[i]->get_geometry();
 
-               if(y)
-                       y -= row_h;
-               if(record_rows && i>0)
+               if(view_mode!=GRID || (x>0 && x+igeom.w>view_w))
                {
-                       rows.back().height = row_h;
-                       rows.push_back(i);
+                       x = 0;
+                       if(y)
+                               y -= row_h;
+                       if(record_rows && i>0)
+                       {
+                               rows.back().height = row_h;
+                               rows.push_back(i);
+                       }
+                       row_h = 0;
                }
-               row_h = 0;
 
                if(first_row<rows.size() && i==rows[first_row].first)
                        y = geom.h-min(geom.h, margin.top);
@@ -404,7 +448,8 @@ void List::reposition_items(bool record_rows)
                else if(igeom.h+margin.bottom<=y)
                {
                        items[i]->set_visible(true);
-                       items[i]->set_geometry(Geometry(margin.left, y-igeom.h, view_w, igeom.h));
+                       unsigned iw = (view_mode==GRID ? igeom.w : view_w);
+                       items[i]->set_geometry(Geometry(margin.left+x, y-igeom.h, iw, igeom.h));
                }
                else
                {
@@ -413,6 +458,7 @@ void List::reposition_items(bool record_rows)
                        y = 0;
                }
 
+               x += igeom.w;
                row_h = max(row_h, igeom.h);
        }
 
@@ -671,7 +717,9 @@ List::Loader::Loader(List &l):
        DataFile::DerivedObjectLoader<List, Widget::Loader>(l)
 {
        add("item", &Loader::item);
+       add("view_mode", &List::view_mode);
        add("view_size", &List::view_rows);
+       add("view_size", &List::view_rows, &List::view_columns);
 }
 
 void List::Loader::item(const string &v)
@@ -679,5 +727,17 @@ void List::Loader::item(const string &v)
        dynamic_cast<BasicListData<string> &>(*obj.data).append(v);
 }
 
+
+void operator>>(const LexicalConverter &conv, List::ViewMode &vm)
+{
+       const string &str = conv.get();
+       if(str=="LIST")
+               vm = List::LIST;
+       else if(str=="GRID")
+               vm = List::GRID;
+       else
+               throw lexical_error(format("conversion of '%s' to List::ViewMode", str));
+}
+
 } // namespace GLtk
 } // namespace Msp
index ef4311e0702c73b818a19ab3abaadb07e1427abb..1de05f6490b840b06193e9fa4f7ba133fb258dce 100644 (file)
@@ -30,6 +30,12 @@ to allow scrolling through a long list.
 class List: virtual public Widget, private Container
 {
 public:
+       enum ViewMode
+       {
+               LIST,
+               GRID
+       };
+
        class Loader: public DataFile::DerivedObjectLoader<List, Widget::Loader>
        {
        public:
@@ -148,11 +154,13 @@ private:
        bool own_data;
        DataObserver *observer;
        ItemFactory *item_factory;
+       ViewMode view_mode;
        int sel_index;
        int focus_index;
        unsigned first_row;
        unsigned max_scroll;
        unsigned view_rows;
+       unsigned view_columns;
        const Part *items_part;
        bool ignore_slider_change;
        bool dragging;
@@ -195,7 +203,9 @@ private:
        Item *create_item(unsigned);
 
 public:
+       void set_view_mode(ViewMode);
        void set_view_size(unsigned);
+       void set_view_size(unsigned, unsigned);
        void set_view_all();
 
        void set_selected_index(int);
@@ -230,6 +240,8 @@ private:
        static void adjust_index(int &, int, int);
 };
 
+void operator>>(const LexicalConverter &, List::ViewMode &);
+
 } // namespace GLtk
 } // namespace Msp