From 1c15570729bbce44f0518373ca5bf8bf41cfa3b3 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 20 Feb 2015 17:44:56 +0200 Subject: [PATCH] Support directionality for zones --- source/designer/zoneproperties.cpp | 40 +++++++++- source/designer/zoneproperties.h | 2 + source/libr2c2/trackchain.cpp | 50 +++++++++++++ source/libr2c2/trackchain.h | 13 ++++ source/libr2c2/zone.cpp | 116 ++++++++++++++++++++++++++++- source/libr2c2/zone.h | 11 +++ 6 files changed, 230 insertions(+), 2 deletions(-) diff --git a/source/designer/zoneproperties.cpp b/source/designer/zoneproperties.cpp index 6ea4f2a..38d9cc7 100644 --- a/source/designer/zoneproperties.cpp +++ b/source/designer/zoneproperties.cpp @@ -2,14 +2,25 @@ #include #include #include +#include "libr2c2/block.h" +#include "libr2c2/track.h" #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): - zone(z) + zone(z), + up_directions(&track_block_name) { set_layout(new GLtk::Layout); GLtk::Column col(*layout); @@ -50,6 +61,27 @@ ZoneProperties::ZoneProperties(Zone &z): 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; { @@ -73,5 +105,11 @@ void ZoneProperties::on_response(int code) qualifier = drp_qualifier->get_data().get_string(sel); unsigned number = lexical_cast(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); } } diff --git a/source/designer/zoneproperties.h b/source/designer/zoneproperties.h index a69d02a..c27cadb 100644 --- a/source/designer/zoneproperties.h +++ b/source/designer/zoneproperties.h @@ -13,6 +13,8 @@ private: Msp::GLtk::Entry *ent_group; Msp::GLtk::Dropdown *drp_qualifier; Msp::GLtk::Entry *ent_number; + Msp::GLtk::FunctionListData up_directions; + Msp::GLtk::Dropdown *drp_up_direction; public: ZoneProperties(R2C2::Zone &); diff --git a/source/libr2c2/trackchain.cpp b/source/libr2c2/trackchain.cpp index 0c3282a..f354c6e 100644 --- a/source/libr2c2/trackchain.cpp +++ b/source/libr2c2/trackchain.cpp @@ -1,9 +1,11 @@ +#include #include #include "layout.h" #include "track.h" #include "trackchain.h" using namespace std; +using namespace Msp; namespace R2C2 { @@ -135,6 +137,29 @@ bool TrackChain::has_track(Track &t) const 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]; @@ -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 diff --git a/source/libr2c2/trackchain.h b/source/libr2c2/trackchain.h index 7d3c518..7102e56 100644 --- a/source/libr2c2/trackchain.h +++ b/source/libr2c2/trackchain.h @@ -23,6 +23,13 @@ public: class TrackChain: public sigc::trackable { public: + enum Direction + { + UNSPECIFIED, + UP, + DOWN + }; + typedef std::set TrackSet; protected: @@ -63,6 +70,8 @@ private: 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: @@ -72,6 +81,10 @@ public: virtual Msp::DataFile::Statement save_reference() const = 0; }; + +void operator<<(Msp::LexicalConverter &, TrackChain::Direction); +void operator>>(const Msp::LexicalConverter &, TrackChain::Direction &); + } // namespace R2C2 #endif diff --git a/source/libr2c2/zone.cpp b/source/libr2c2/zone.cpp index 8b6c95f..52e3c28 100644 --- a/source/libr2c2/zone.cpp +++ b/source/libr2c2/zone.cpp @@ -12,7 +12,8 @@ namespace R2C2 { Zone::Zone(Layout &l): TrackChain(l), - number(0) + number(0), + up_end(-1) { layout.add(*this); } @@ -54,6 +55,91 @@ void Zone::update_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 &st) const { st.push_back((DataFile::Statement("group"), group)); @@ -75,6 +161,19 @@ void Zone::save(list &st) const 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 @@ -87,6 +186,7 @@ Zone::Loader::Loader(Zone &z): DataFile::ObjectLoader(z) { add("block", &Loader::block); + add("direction_hint", &Loader::direction_hint); 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()); } +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 diff --git a/source/libr2c2/zone.h b/source/libr2c2/zone.h index 9688c34..fc44d4f 100644 --- a/source/libr2c2/zone.h +++ b/source/libr2c2/zone.h @@ -21,12 +21,14 @@ public: private: virtual void finish(); void block(unsigned); + void direction_hint(unsigned, Direction); }; private: std::string group; std::string qualifier; unsigned number; + int up_end; public: Zone(Layout &); @@ -41,6 +43,15 @@ public: 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 &) const; virtual Msp::DataFile::Statement save_reference() const; }; -- 2.45.2