]> git.tdb.fi Git - r2c2.git/commitdiff
Support directionality for zones
authorMikko Rasa <tdb@tdb.fi>
Fri, 20 Feb 2015 15:44:56 +0000 (17:44 +0200)
committerMikko Rasa <tdb@tdb.fi>
Fri, 20 Feb 2015 15:47:29 +0000 (17:47 +0200)
source/designer/zoneproperties.cpp
source/designer/zoneproperties.h
source/libr2c2/trackchain.cpp
source/libr2c2/trackchain.h
source/libr2c2/zone.cpp
source/libr2c2/zone.h

index 6ea4f2a330fc1a4b115a597933b01ede9813968d..38d9cc792bc9e7f37da6943dc808b3e8a7ee10bd 100644 (file)
@@ -2,14 +2,25 @@
 #include <msp/gltk/column.h>
 #include <msp/gltk/label.h>
 #include <msp/gltk/row.h>
 #include <msp/gltk/column.h>
 #include <msp/gltk/label.h>
 #include <msp/gltk/row.h>
+#include "libr2c2/block.h"
+#include "libr2c2/track.h"
 #include "zoneproperties.h"
 
 using namespace std;
 using namespace Msp;
 using namespace R2C2;
 
 #include "zoneproperties.h"
 
 using namespace std;
 using namespace Msp;
 using namespace R2C2;
 
+string track_block_name(Track *const &track)
+{
+       if(track)
+               return track->get_block().get_name();
+       else
+               return "(unspecified)";
+}
+
 ZoneProperties::ZoneProperties(Zone &z):
 ZoneProperties::ZoneProperties(Zone &z):
-       zone(z)
+       zone(z),
+       up_directions(&track_block_name)
 {
        set_layout(new GLtk::Layout);
        GLtk::Column col(*layout);
 {
        set_layout(new GLtk::Layout);
        GLtk::Column col(*layout);
@@ -50,6 +61,27 @@ ZoneProperties::ZoneProperties(Zone &z):
                ent_number->set_edit_size(4, 1);
        }
 
                ent_number->set_edit_size(4, 1);
        }
 
+       {
+               GLtk::Row row(*layout);
+               add(*(lbl2 = new GLtk::Label("Up towards")));
+               layout->add_constraint(*lbl1, GLtk::Layout::COPY_WIDTH, *lbl2);
+               add(*(drp_up_direction = new GLtk::Dropdown(up_directions)));
+
+               up_directions.append(0);
+
+               Track *up = zone.get_end(TrackChain::UP).next().track();
+               if(!up)
+                       drp_up_direction->set_selected_index(0);
+
+               for(unsigned i=0; i<2; ++i)
+                       if(TrackIter iter = zone.get_end(i).next())
+                       {
+                               up_directions.append(iter.track());
+                               if(iter.track()==up)
+                                       drp_up_direction->set_selected_index(up_directions.size()-1);
+                       }
+       }
+
        GLtk::Button *btn;
 
        {
        GLtk::Button *btn;
 
        {
@@ -73,5 +105,11 @@ void ZoneProperties::on_response(int code)
                        qualifier = drp_qualifier->get_data().get_string(sel);
                unsigned number = lexical_cast<unsigned>(ent_number->get_text());
                zone.set_name(ent_group->get_text(), qualifier, number);
                        qualifier = drp_qualifier->get_data().get_string(sel);
                unsigned number = lexical_cast<unsigned>(ent_number->get_text());
                zone.set_name(ent_group->get_text(), qualifier, number);
+
+               sel = drp_up_direction->get_selected_index();
+               if(sel==0)
+                       zone.clear_direction();
+               else
+                       zone.set_direction_towards(*up_directions.get(sel), TrackChain::UP);
        }
 }
        }
 }
index a69d02a984b4e4a48b76855ea61fc51f64a30bb3..c27cadb54e4a22e623931cf0d840211288d7fafb 100644 (file)
@@ -13,6 +13,8 @@ private:
        Msp::GLtk::Entry *ent_group;
        Msp::GLtk::Dropdown *drp_qualifier;
        Msp::GLtk::Entry *ent_number;
        Msp::GLtk::Entry *ent_group;
        Msp::GLtk::Dropdown *drp_qualifier;
        Msp::GLtk::Entry *ent_number;
+       Msp::GLtk::FunctionListData<R2C2::Track *> up_directions;
+       Msp::GLtk::Dropdown *drp_up_direction;
 
 public:
        ZoneProperties(R2C2::Zone &);
 
 public:
        ZoneProperties(R2C2::Zone &);
index 0c3282ad4845a4893f2c776fef7d2f49d2c48413..f354c6eac7054fb0d9f6c4c59f30578981e33acf 100644 (file)
@@ -1,9 +1,11 @@
+#include <msp/strings/format.h>
 #include <msp/strings/utils.h>
 #include "layout.h"
 #include "track.h"
 #include "trackchain.h"
 
 using namespace std;
 #include <msp/strings/utils.h>
 #include "layout.h"
 #include "track.h"
 #include "trackchain.h"
 
 using namespace std;
+using namespace Msp;
 
 namespace R2C2 {
 
 
 namespace R2C2 {
 
@@ -135,6 +137,29 @@ bool TrackChain::has_track(Track &t) const
        return tracks.count(&t);
 }
 
        return tracks.count(&t);
 }
 
+TrackIter TrackChain::iter_for(Track &t, Direction d) const
+{
+       if(!tracks.count(&t))
+               return TrackIter();
+       else if(d==UNSPECIFIED)
+               return TrackIter(&t, 0);
+       else
+               return TrackIter();
+}
+
+TrackIter TrackChain::get_end(unsigned i) const
+{
+       if(i>=2)
+               throw invalid_argument("TrackChain::get_end");
+
+       if(!ends[0])
+               return TrackIter();
+       else if(i==1 && !ends[1])
+               return ends[0].reverse();
+       else
+               return ends[i];
+}
+
 bool TrackChain::is_loop() const
 {
        return !tracks.empty() && !ends[0] && !ends[1];
 bool TrackChain::is_loop() const
 {
        return !tracks.empty() && !ends[0] && !ends[1];
@@ -151,4 +176,29 @@ void TrackChain::object_removed(Object &obj)
        }
 }
 
        }
 }
 
+
+void operator<<(LexicalConverter &conv, TrackChain::Direction dir)
+{
+       switch(dir)
+       {
+       case TrackChain::UNSPECIFIED: conv.result("UNSPECIFIED"); return;
+       case TrackChain::UP: conv.result("UP"); return;
+       case TrackChain::DOWN: conv.result("DOWN"); return;
+       default: throw lexical_error(format("conversion of Direction(%d) to string", dir));
+       }
+}
+
+void operator>>(const LexicalConverter &conv, TrackChain::Direction &dir)
+{
+       const string &str = conv.get();
+       if(str=="UNSPECIFIED")
+               dir = TrackChain::UNSPECIFIED;
+       else if(str=="UP")
+               dir = TrackChain::UP;
+       else if(str=="DOWN")
+               dir = TrackChain::DOWN;
+       else
+               throw lexical_error(format("conversion of '%s' to Direction", str));
+}
+
 } // namespace R2C2
 } // namespace R2C2
index 7d3c518a92842aa076350b701182b7fd6054df86..7102e5659445062765793ac5d349894f36a649db 100644 (file)
@@ -23,6 +23,13 @@ public:
 class TrackChain: public sigc::trackable
 {
 public:
 class TrackChain: public sigc::trackable
 {
 public:
+       enum Direction
+       {
+               UNSPECIFIED,
+               UP,
+               DOWN
+       };
+
        typedef std::set<Track *> TrackSet;
 
 protected:
        typedef std::set<Track *> TrackSet;
 
 protected:
@@ -63,6 +70,8 @@ private:
 public:
        const TrackSet &get_tracks() const { return tracks; }
        bool has_track(Track &) const;
 public:
        const TrackSet &get_tracks() const { return tracks; }
        bool has_track(Track &) const;
+       virtual TrackIter iter_for(Track &, Direction) const;
+       TrackIter get_end(unsigned) const;
        bool is_loop() const;
 
 private:
        bool is_loop() const;
 
 private:
@@ -72,6 +81,10 @@ public:
        virtual Msp::DataFile::Statement save_reference() const = 0;
 };
 
        virtual Msp::DataFile::Statement save_reference() const = 0;
 };
 
+
+void operator<<(Msp::LexicalConverter &, TrackChain::Direction);
+void operator>>(const Msp::LexicalConverter &, TrackChain::Direction &);
+
 } // namespace R2C2
 
 #endif
 } // namespace R2C2
 
 #endif
index 8b6c95f9c9af2fd0911c956e76fe44e15cfb0362..52e3c281d8175254474cef140ea4217774c3c3e9 100644 (file)
@@ -12,7 +12,8 @@ namespace R2C2 {
 
 Zone::Zone(Layout &l):
        TrackChain(l),
 
 Zone::Zone(Layout &l):
        TrackChain(l),
-       number(0)
+       number(0),
+       up_end(-1)
 {
        layout.add(*this);
 }
 {
        layout.add(*this);
 }
@@ -54,6 +55,91 @@ void Zone::update_name()
        TrackChain::set_name(full_name);
 }
 
        TrackChain::set_name(full_name);
 }
 
+void Zone::set_direction_towards(Track &track, Direction dir)
+{
+       if(dir==UNSPECIFIED)
+               throw invalid_argument("Zone::set_direction_towards");
+       if(tracks.empty())
+               throw logic_error("no tracks");
+       if(tracks.count(&track))
+               throw invalid_argument("Zone::set_direction_towards");
+
+       Validity valid = check_validity(track);
+       if(valid!=VALID)
+               throw_bad_chain(valid);
+
+       for(unsigned i=0; i<2; ++i)
+               if(ends[i] && ends[i]->get_link_slot(track)>=0)
+               {
+                       up_end = (dir==UP ? i : 1-i);
+                       return;
+               }
+
+       throw logic_error("internal error (valid track not linked to ends)");
+}
+
+void Zone::clear_direction()
+{
+       up_end = -1;
+}
+
+TrackIter Zone::iter_for(Track &track, Direction dir) const
+{
+       if(!tracks.count(&track))
+               return TrackIter();
+       else if(dir==UNSPECIFIED)
+               return TrackIter(&track, 0);
+       else if(up_end<0)
+               return TrackIter();
+
+       for(int i=0; i<2; ++i)
+               if(&track==ends[i].track())
+               {
+                       if((i==up_end)==(dir==UP))
+                               return ends[i];
+                       else
+                               return ends[i].reverse();
+               }
+
+       TrackIter iter = ends[up_end^(dir==UP)].reverse();
+       while(iter && tracks.count(iter.track()))
+       {
+               if(iter.track()==&track)
+                       return iter;
+
+               iter = next_iter(iter);
+       }
+
+       return TrackIter();
+}
+
+TrackIter Zone::get_end(Direction dir) const
+{
+       if(dir==UNSPECIFIED)
+               return ends[0];
+       if(up_end<0)
+               return TrackIter();
+
+       return ends[up_end^(dir==DOWN)];
+}
+
+TrackIter Zone::next_iter(const TrackIter &iter) const
+{
+       TrackIter next_outside;
+       const TrackType::Endpoint &ep = iter.endpoint();
+       for(unsigned i=0; ep.paths>>i; ++i)
+               if(ep.has_path(i))
+                       if(TrackIter next = iter.next(i))
+                       {
+                               if(tracks.count(next.track()))
+                                       return next;
+                               else
+                                       next_outside = next;
+                       }
+
+       return next_outside;
+}
+
 void Zone::save(list<DataFile::Statement> &st) const
 {
        st.push_back((DataFile::Statement("group"), group));
 void Zone::save(list<DataFile::Statement> &st) const
 {
        st.push_back((DataFile::Statement("group"), group));
@@ -75,6 +161,19 @@ void Zone::save(list<DataFile::Statement> &st) const
 
                iter = next_iter(iter);
        }
 
                iter = next_iter(iter);
        }
+
+       if(up_end>=0)
+       {
+               for(unsigned i=0; i<2; ++i)
+               {
+                       TrackIter hint = next_iter(ends[up_end^i]);
+                       if(hint && !tracks.count(hint.track()))
+                       {
+                               st.push_back((DataFile::Statement("direction_hint"), hint->get_block().get_id(), (i==0 ? UP : DOWN)));
+                               break;
+                       }
+               }
+       }
 }
 
 DataFile::Statement Zone::save_reference() const
 }
 
 DataFile::Statement Zone::save_reference() const
@@ -87,6 +186,7 @@ Zone::Loader::Loader(Zone &z):
        DataFile::ObjectLoader<Zone>(z)
 {
        add("block",     &Loader::block);
        DataFile::ObjectLoader<Zone>(z)
 {
        add("block",     &Loader::block);
+       add("direction_hint", &Loader::direction_hint);
        add("group",     &Zone::group);
        add("number",    &Zone::number);
        add("qualifier", &Zone::qualifier);
        add("group",     &Zone::group);
        add("number",    &Zone::number);
        add("qualifier", &Zone::qualifier);
@@ -103,4 +203,18 @@ void Zone::Loader::block(unsigned b)
        obj.add_tracks(blk.get_tracks());
 }
 
        obj.add_tracks(blk.get_tracks());
 }
 
+void Zone::Loader::direction_hint(unsigned b, Direction d)
+{
+       Block &blk = obj.layout.get_block(b);
+       const TrackSet &btracks = blk.get_tracks();
+       for(TrackSet::const_iterator i=btracks.begin(); i!=btracks.end(); ++i)
+               if(obj.check_validity(**i)==VALID)
+               {
+                       obj.set_direction_towards(**i, d);
+                       return;
+               }
+
+       throw invalid_argument("Zone::Loader::direction_hint");
+}
+
 } // namespace R2C2
 } // namespace R2C2
index 9688c3419540bcf17173bcfbd49d853875f426ff..fc44d4f205de91ad88bc3b7458310f2a39287996 100644 (file)
@@ -21,12 +21,14 @@ public:
        private:
                virtual void finish();
                void block(unsigned);
        private:
                virtual void finish();
                void block(unsigned);
+               void direction_hint(unsigned, Direction);
        };
 
 private:
        std::string group;
        std::string qualifier;
        unsigned number;
        };
 
 private:
        std::string group;
        std::string qualifier;
        unsigned number;
+       int up_end;
 
 public:
        Zone(Layout &);
 
 public:
        Zone(Layout &);
@@ -41,6 +43,15 @@ public:
        const std::string &get_qualifier() const { return qualifier; }
        unsigned get_number() const { return number; }
 
        const std::string &get_qualifier() const { return qualifier; }
        unsigned get_number() const { return number; }
 
+       void set_direction_towards(Track &, Direction);
+       void clear_direction();
+       virtual TrackIter iter_for(Track &, Direction) const;
+private:
+       TrackIter next_iter(const TrackIter &) const;
+public:
+       using TrackChain::get_end;
+       TrackIter get_end(Direction) const;
+
        void save(std::list<Msp::DataFile::Statement> &) const;
        virtual Msp::DataFile::Statement save_reference() const;
 };
        void save(std::list<Msp::DataFile::Statement> &) const;
        virtual Msp::DataFile::Statement save_reference() const;
 };