#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;
+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);
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;
{
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);
}
}
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 &);
+#include <msp/strings/format.h>
#include <msp/strings/utils.h>
#include "layout.h"
#include "track.h"
#include "trackchain.h"
using namespace std;
+using namespace Msp;
namespace R2C2 {
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];
}
}
+
+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
class TrackChain: public sigc::trackable
{
public:
+ enum Direction
+ {
+ UNSPECIFIED,
+ UP,
+ DOWN
+ };
+
typedef std::set<Track *> TrackSet;
protected:
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:
virtual Msp::DataFile::Statement save_reference() const = 0;
};
+
+void operator<<(Msp::LexicalConverter &, TrackChain::Direction);
+void operator>>(const Msp::LexicalConverter &, TrackChain::Direction &);
+
} // namespace R2C2
#endif
Zone::Zone(Layout &l):
TrackChain(l),
- number(0)
+ number(0),
+ up_end(-1)
{
layout.add(*this);
}
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));
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::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);
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
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 &);
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;
};