// MediaRoutingView.h
// e.moon 6may99
//
// PURPOSE
//   Provide a simple interface for the BeOS/Genki media system.
//   Displays all the currently running ('live') media nodes
//   in a grid, and represents the connections between them
//   visually.
//
// NOTES
//
// *** 24aug99: there are WAY too many virtuals in here! *** +++++
//
// * 27may99 e.moon
// - fixed displaceCells() bug -- only added rows/columns when
//   cell(s) had to be moved.
//
// * 21may99 e.moon
// - optimizing wire re-routing during drag operations:
//   . m_displacedWires is now a set, which insures (rather
//     efficiently) that each wire will only be re-routed once.
//
//   . routeWire()
//     leaves existing wire segments untouched if possible; wire
//		 segments may added or removed from both the Wire object
//     and the grid.  New or removed segments are copied to the
//     m_touchedSegments set to ensure that they area they covered
//     is redrawn as efficiently as possible.
//         
// * 18may99 e.moon
// - displace API change: displaceCells() now takes a column/row
//   coordinate, a direction, and the number of cells to displace;
//   it returns the number of cells successfully moved.  This will
//   make cell-dragging much more straightforward.
//
// * 17may99 e.moon
// - Reworking the 'displace' mechanism: to smooth out the UI a
//   bit, I've decided to make the cells (node views) act like
//   solid blocks: when dragged, any cells in the way of their
//   destination are pushed in the direction they were dragged.
//   If a blocking cell can't be pushed, the dragged cell isn't
//   moved.
//   (this means the end of the 'displace undo' mechanism -- which
//    was an interesting exercise, but a bit confusing to use.)
//
// ! In addition, the grid will now maintain an empty row and column
//   (bottom/right most) at all times; the scroll bars should be adjusted
//   to not count the empty row/column as 'data area'. +++++
//
// * 10may99 e.moon
//   design/whoops! -- it's time to abolish the 'slot' object.
//   the only actual views in the grid container-view should be
//   node representations.  All NodeSlotView does is make sure
//   that it contains either a single node view, or none at all,
//   as well as doing some drawing that could be done much more
//   intuitively by the container view.
//
// * 8may99 e.moon
// - Time to start thinking about UI/dragging operations.  Should
//   roster message handling be suspended while the user is dragging
//   a node or connection around?  I probably wouldn't want nodes 
//   appearing or resizing while I'm making a connection.  Unhandled
//   messages could be queued up in a list to be handled once the
//   user's done dragging.  
//
// - This leads to another sticky issue: how should nodes that
//   dynamically add inputs/outputs be handled (such as the Be Mixer?)
//   If a connection took place while the user was dragging an
//   output towards what was once a free input, it may or may not
//   still be free.
//   * solution A: if a free input goes away, look for a new free
//     input that supports the same format.  If one was found,
//     pretend it was the same input all along.
//   * solution B: for the Be Mixer (and other user-selected nodes)
//     display a single free-input icon, and fetch a real free input
//     as needed.  (this complements solution A nicely.)
//
// - The grid should always display one more row or column than is
//   being used; this obviates the need for clunky 'add row'-type
//   commands.  If the user drags a node on top of another, or into
//   a slot that can't expand enough without hitting occupied slots
//   below, it should Just Work(tm): the occupied slots should be
//   displaced downwards, and new rows should be created if need be.
//   Dragged nodes should be moved 'for real' as the user drags,
//   but displacement should be undoable: even if the user drags onto
//   an occupied slot and a new row is created to make room, the
//   previous arrangement should snap back into place as the user
//   keeps dragging.  This is a tall order, but it will make a much
//   more intuitive and elegant tool.  *** Another touch to add later:
//   displace node upwards if the user drags the 'middle of it' (a
//   slot other than the cell origin) but only if there's room above. ***
//
// - There are some hardcoded structure rules that should probably
//   be defined somewhere central.  The MediaRoutingView extends
//   the basic GridView by adding the concept of 'node columns' and
//   'node rows'.  These are the columns/rows in which slots are
//   placed that hold actual node representations.  These slots are
//   bounded on all sides by columns/rows through which wires
//   (connections) are routed -- these columns/rows are referred to
//   as gutters.
//
// - For a grid with 'n' number of node columns, there will be
//   1+(n*2) actual GridView column objects, n+1 of which are
//   GutterColumn instances, and n of which are NodeColumn instances.
//   GutterColumn and NodeColumn derive from the base class
//   RoutingColumn, which maintains a list of wire segments that
//   overlap the column for fast lookup.  The same logic and class
//   structure holds for rows.  (rows and columns are treated in such
//   a similar fashion that I'm starting to regret making a distinction
//   between the two at class level -- but it would probably be a
//   bigger headache otherwise.  What the hell do you call something
//   that can be either a row or a column?)
//
// HISTORY
//   e.moon 6may99: first stab

#ifndef __MEDIAROUTINGVIEW__H__
#define __MEDIAROUTINGVIEW__H__

#include <list>
#include <map>
#include <utility>
#include <set>
#include <vector>

// forward class declarations
class BMediaRoster;
class BRegion;

//class Transport;

// parent class: a simple grid-based view layout manager
#include "GridView.h"

// mouse-tracking interface
#include "MouseTrackingHelpers.h"

#include <MediaDefs.h>
#include <MediaNode.h>
#include <Font.h>
#include <Locker.h>

#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE

class Wire;
class WireSegment;
class WireVertex;
class LiveNodeView;

class MediaRoutingContainerView;

class RoutingColumn;
class RoutingRow;
class NodeColumn;
class NodeRow;
class GutterColumn;
class GutterRow;

// 11aug99
class NodeManager;
class NodeGroup;
class NodeRef;
class Connection;

class MediaRoutingView :
	public		IMouseTrackingDestination,
	public		GridView {
	typedef		GridView _inherited;
	
	friend class MediaRoutingContainerView;
	
	friend class LiveNodeView;

public:					//  message types
	enum message_t {
		// INBOUND
		// set font:
		// "family"		string:			the font family
		// "style"		string:			the font style
		// "code"			[u]int32:		the family/style code -- can be sent instead of
		//												family & style strings (but what if the list of
		//												installed fonts changes before this message is
		//												handled? +++++
		// "size"			float:			font size in points
		// "face"			[u]int16:		face (bold, italics, etc.) flags
		M_SET_FONT									=MediaRoutingView_message_base,
		
		// INBOUND
		// release/delete node
		// "nodeID"		[u]int32:		node to release
		M_RELEASE_NODE,
		
		// OUTBOUND
		// describes a selected node (sent to owning window)
		// "nodeID"		int32
		M_NODE_SELECTED,
		
		// OUTBOUND
		// describes a selected group (sent to owning window)
		// "groupID"	int32
		M_GROUP_SELECTED,
		
		// INBOUND
		// requests that the currently selected node/group be broadcast
		// back to the owning window
		M_BROADCAST_SELECTION
	};

public:													// members
	NodeManager* const						manager;
	
public:													// ctor/dtor/accessors
	virtual ~MediaRoutingView();
	
	MediaRoutingView(
		NodeManager*								_manager,
		BRect												frame,
		const char*									name,
		uint32											resizeMode=B_FOLLOW_ALL_SIDES);

public:													// IMouseTrackingDestination impl.

	// a MouseTrackingSourceView has started tracking the mouse
	// (point is in screen coordinates)
	virtual void mouseTrackingBegin(
		MouseTrackingSourceView*		source,
		uint32											buttons,
		BPoint											point);
	
	// mouse-tracking update from child view
	// (point is in screen coordinates)
	virtual void mouseTrackingUpdate(
		uint32											buttons,
		float												xDelta,
		float												yDelta,
		BPoint											point);
	
	// mouse-tracking done
	virtual void mouseTrackingEnd();
	
private:												// mouse-tracking impl. methods
	void beginCellDrag(
		uint32											buttons,
		BPoint											point);
	void updateCellDrag(
		uint32											buttons,
		float												xDelta,
		float												yDelta,
		BPoint											point);
	void endCellDrag();

	void beginWireDrag(
		uint32											buttons,
		BPoint											point);
	void updateWireDrag(
		uint32											buttons,
		float												xDelta,
		float												yDelta,
		BPoint											point);
	void endWireDrag();
	
	BRect jackOutlineBounds(
		const WireVertex*						vertex);
	void drawJackOutline(
		const WireVertex*						vertex);

	// find vertex under the given screen point
	// +++++ accept media_format from the origin jack (the other side of
	//       the connection)
	//       - only return true if the connection looks likely to succeed
	bool findAvailableVertex(
		BPoint											point,
		WireVertex&									outVertex);

public:					// BView impl
	virtual void AttachedToWindow();
	virtual void AllAttached();
	virtual void DetachedFromWindow();
	
	virtual void Draw(
		BRect												updateRect);
	
	// +++++ use drawWireSegment()
	virtual void DrawAfterChildren(
		BRect												updateRect);
	
	virtual void KeyDown(
		const char*									bytes,
		int32												count);
		
	// clear selection [e.moon 11oct99]
	virtual void MouseDown(
		BPoint											where);

	virtual void Pulse();	

protected:											// keypress handlers
	virtual void handleDeleteKey();
	
public:													// BHandler impl
	virtual void MessageReceived(
		BMessage*										msg);

protected:											// internal message-handling helpers
	virtual void setFont(
		BMessage*										msg);
	virtual void releaseNode(
		BMessage*										msg);
	
protected:											// BMediaRoster message-handling helpers
	virtual void nodesCreated(
		BMessage*										msg);

	virtual void nodesDeleted(
		BMessage*										msg);
		
	virtual void connectionMade(
		BMessage*										msg);
		
	virtual void connectionBroken(
		BMessage*										msg);

	// NodeRef message handlers
	
	virtual void releaseNodeRef(
		BMessage*										msg);

	// DormantNodeView message handlers

	virtual void instantiateNode(
		BMessage*										msg);

	virtual void handleTrackerDrop(
		BMessage*										msg);

// removed 11aug99
//private:												// connection/transport helpers
//
//	// add child-cell references for every node in the given transport
//	virtual void addTransportRefs(Transport* pTransport);
//	
//	// remove child-cell references for every node in the given transport
//	virtual void removeTransportRefs(Transport* pTransport);
//
//	void initTransports();

protected:											// outbound messaging (notification)
	void notifyNodeSelected(
		uint32											nodeID);

	void notifyGroupSelected(
		uint32											groupID);
	
protected:											// types & constants
	enum column_gutter_t {
		LEFT_GUTTER,
		RIGHT_GUTTER
	};
	enum row_gutter_t {
		TOP_GUTTER,
		BOTTOM_GUTTER
	};
	
	enum displace_t {
		DISPLACE_LEFT,
		DISPLACE_UP,
		DISPLACE_RIGHT,
		DISPLACE_DOWN
	};

protected:											// node & gutter row/column access

	// *** these methods find real GridView row/column index
	//     given a node or gutter index/location
	
	// convert node-row index to grid row index
	uint32 nodeToGridRowIndex(
		uint32											index) const;

	// convert grid row index to node row index
	// assertion fails if row isn't odd!
	uint32 gridToNodeRowIndex(
		uint32											row) const;
	
	NodeRow* nodeRow(
		uint32											index) const;
		
	uint32 nodeRows() const;
	
	// figure a row-span from the given height in pixels
	uint32 nodeRowSpanFor(
		float												height) const;
	
	// convert node-column index to grid column index
	inline uint32 nodeToGridColumnIndex(
		uint32											index) const;

	// convert grid column index to node column
	// assertion fails if column isn't odd!
	inline uint32 gridToNodeColumnIndex(
		uint32											column) const;

	inline NodeColumn* nodeColumn(
		uint32											index) const;
		
	inline uint32 nodeColumns() const;

	// *** gutter row/column access

	inline uint32 gutterRowIndex(
		uint32											index,
		row_gutter_t								pos) const;

	inline GutterRow* gutterRow(
		uint32											index,
		row_gutter_t								pos) const;
	
	inline uint32 gutterColumnIndex(
		uint32											index,
		column_gutter_t							pos) const;

	inline GutterColumn* gutterColumn(
		uint32											index,
		column_gutter_t							pos) const;
	
	// *** vertex-based row/column lookup

	uint32 gridRowIndexFor(
		const WireVertex&						vertex) const;

	RoutingRow* rowFor(
		const WireVertex&						vertex) const;

	uint32 gridColumnIndexFor(
		const WireVertex&						vertex) const;

	RoutingColumn* columnFor(
		const WireVertex&						vertex) const;
	
	// convert node row span to grid row span
	uint32 nodeToGridRowSpan(
		uint32											nodeRowSpan) const;
	
	// convert grid row span to node row span
	// (an assertion will fail given an invalid node-row span, ie.
	//  an even number.)
	uint32 gridToNodeRowSpan(
		uint32											gridRowSpan) const;

protected:				// row/column operations
	
	// add/remove node row (+ manage wires)
	// (index specifies node row)
	void addNodeRow(
		uint32											index,
		bool												rerouteWires=true);

	bool nodeRowEmpty(
		uint32											index) const;

	// row must be empty
	void deleteNodeRow(
		uint32											index,
		bool												rerouteWires=true);
	
	// add/remove node column (+ manage wires)
	// (index specifies node column)
	void addNodeColumn(
		uint32											index,
		bool												rerouteWires=true);

	bool nodeColumnEmpty(
		uint32											index) const;

	// column must be empty
	void deleteNodeColumn(
		uint32											index,
		bool 												rerouteWires=true);

protected:				// node-view operations

	// fetch given node view
	LiveNodeView* nodeViewAt(
		uint32											nodeColumn,
		uint32											nodeRow,
		uint32*											poNodeRows=0) const;
		
	LiveNodeView* nodeViewFor(
		media_node_id								id,
		uint32*											poNodeColumn=0,
		uint32*											poNodeRow=0) const;
	
	// fetch node rowspan of given slot
	// (an assertion fails if the slot couldn't be found)
	uint32 nodeViewRows(
		uint32											nodeColumn,
		uint32											nodeRow) const;

	// add node
	// - new columns & rows are created, and blocking cells moved, as
	//   necessary to place the node in the requested position.
	
	void addNodeView(
		LiveNodeView*								pNodeView,
		uint32											nodeColumn,
		uint32											nodeRow);
	
	// remove node
	// now specified via column/row for API consistency
	// [17may99]
	
	void deleteNodeView(
		uint32											nodeColumn,
		uint32											nodeRow);

	// move node (+ associated wires)
	//       no longer tries to displace cells that are in the way;
	//       that's the caller's responsibility
	// * the destination column/row MUST be free, or an assert will fail
	//
	// 19may99: if bRerouteWires is false, any wires that needed to be
	//          relocated are stored in m_displacedWires, and it's your
	//          responsibility to handle them (typically by calling
	//          rerouteDisplacedWires().)

	void moveNodeView(
		uint32											fromColumn,
		uint32											fromRow,
		uint32											toColumn,
		uint32											toRow,
		bool												rerouteWires=true);
		
	// resize node view to given number of rows: this should Just Work(tm),
	// which means that occupied slots below the given row may need
	// to be pushed downwards, and that new rows may need to be created
	// at the bottom of the grid.
	
	void resizeNodeView(
		uint32											nodeColumn,
		uint32											nodeRow,
		uint32											toNodeRowSpan);

	// select/deselect node
	void selectCell(
		LiveNodeView*								cell,
		bool												notify =true);
		
	void deselectCell(
		LiveNodeView*								cell,
		bool												notify =true);
		
	void deselectAllCells();
	
	void selectWiresBySource(
		LiveNodeView*								cell);
	void deselectWiresBySource(
		LiveNodeView*								cell);
	
	void selectWire(
		Wire*												wire);
	void deselectWire(
		Wire*												wire);
	void deselectAllWires();
	
	// clear selection (cells and wires)
	void deselectAll();

protected:											// node operation helpers

	// * Populates the grid with all nodes currently in the NodeManager.
	void populateInit(); //nyi

	// * Returns ideal position (column) for the given
	//   (externally created) node
	uint32 externalNodeColumn(
		NodeRef*										ref);

	// * Moves cells blocking the given destination column/row
	//   in the direction specified to free up <count> cell slots.
	//   The provided row span is used only if <direction> is
	//   horizontal.
	//
	// * Creates additional rows and columns as necessary to make room,
	//   and to leave an empty row and column available.
	//
	// * If a wire list is provided, wires that need to be rebuilt
	//   (ie. that were connected to displaced cell(s)) are moved into
	//   it.  Wires will only be rebuilt if no wire list is provided.
	//
	// Returns the number of empty cells available.

	// 18may99: if bMoveCells is false, displaceCells() returns the
	//          displaceable distance without making any changes.
	// 19may99: added bRerouteWires (see moveNodeView() for more info)
	
	uint32 displaceCells(
		int32												nodeColumn,
		int32												nodeRow,
		uint32											nodeRowSpan,
		displace_t									direction,
		uint32											distance,
		bool												moveCells=true,
		bool												rerouteWires=true,
		BView*											ignoreCell=0);

private:					// displace helpers
	uint32 v_displaceCells(
		int32												nodeColumn,
		int32												nodeRow,
		uint32											nodeRowSpan,
		displace_t									direction,
		uint32											distance,
		bool												moveCells,
		BView*											ignoreCell);

	uint32 h_displaceCells(
		int32												nodeColumn,
		int32												nodeRow,
		uint32											nodeRowSpan,
		displace_t									direction,
		uint32											distance,
		bool												moveCells,
		BView*											ignoreCell);

protected:											// drawing

	// redraw the given rectangular region, specified in
	// container-view units
	void invalidateContainerRect(
		BRect												rect);

//	// redraw all rectangles in the given region (which is specified
//	// in container-view units)
//	void invalidateContainerRegion(BRegion* pRegion);
	
	// draw wire
	inline void drawWire(
		Wire*												wire); //nyi
	
	// draw wire segment (using current high color)
	// +++++
	inline void drawWireSegment(
		const WireSegment&					segment); //nyi

protected:				// grid-management

	// add/remove node row(s) (+gutter(s))
	// NO WIRE HANDLING IS DONE
	// +++++ assert that no wires cross the destination row
	void addGridRows(
		uint32											nodeRow,
		uint32											count);

	void deleteGridRows(
		uint32											nodeRow,
		uint32											count);

	// add/remove node column(s) (+gutter(s))
	// NO WIRE HANDLING IS DONE
	// +++++ assert that no wires cross the destination column
	void addGridColumns(
		uint32											nodeColumn,
		uint32											count);
	void deleteGridColumns(
		uint32											nodeColumn,
		uint32											count);
	
protected:											// wire-management

	// adds all the wires touching the given node row or column
	// (including gutters) to m_displacedWires.
	// returns the count of matching wires
	uint32 displaceWiresInNodeColumn(
		uint32											nodeColumn);

	uint32 displaceWiresInNodeRow(
		uint32											nodeRow);

	// adds all wires touching the given, presumably empty node
	// slot to m_displacedWires
	// returns the count of matching wires
	uint32 displaceWiresInSlot(
		uint32											nodeColumn,
		uint32											nodeRow,
		uint32											nodeRowSpan);
		
	// adds all wires touching (connected to input or output jacks
	// of) the given cell view to m_displacedWires
	// returns the count of matching wires
	uint32 displaceAllWiresFor(
		LiveNodeView* 							nodeView);
	
	uint32 displaceInputWiresFor(
		LiveNodeView*								nodeView);
		
	uint32 displaceOutputWiresFor(
		LiveNodeView*								nodeView);
	
	// reroutes all wires from m_displacedWires (which
	// is then emptied)
	void rerouteDisplacedWires();

	// find all wires whose source is the given node
	void findWiresBySourceNode(
		media_node_id								id,
		vector<Wire*>&							wires) const;

	// find all wires whose destination is the given node
	void findWiresByDestinationNode(
		media_node_id								id,
		vector<Wire*>&							wires) const;
	
	// find wire matching the given connection: FAST
	Wire* findWire(
		const Connection&						connection) const;
		
	// find wire matching the given connection: SLOW
	Wire* findWire(
		const media_source&					source,
		const media_destination&		destination) const;

	// add/remove wire to the source/dest maps
	// 20may99: no longer messes with segments
	void addWire(
		Wire*												wire);

	// doesn't delete pWire!
	// 20may99: no longer messes with segments
	void removeWire(
		Wire*												wire);
	
	// doesn't delete wires
	// 20may99: no longer messes with segments
	void removeWires(
		const vector<Wire*>&				wires);
	
	// list all wires (connection names, no segments)
	void dumpWires();
	
	// list all segments in the given wire
	void describeWire(Wire* 			wire);

	// add/remove segment to/from any row/column it touches, and
	// invalidate the area covered.  (If other segments are reordered
	// in the process, their bounding rectangles are invalidated also.)
	
	void addWireSegment(
		const WireSegment&					segment);
		
	void removeWireSegment(
		const WireSegment&					segment);
	
	// add/remove all segments for the given wire
	
	void addAllWireSegments(
		const Wire*									wire);
	void removeAllWireSegments(
		const Wire*									wire);
	
	// find wire route for the connection described by the given Wire
	// instance, and add segments to the wire.  (any pre-existing
	// segments are cleared.)
	// 19may99

	// * renamed, reworked 21may99
	status_t routeWire(
		Wire*												wire);
	
	// routeWire() helper
	void addWireSegmentAt(
		Wire*												wire,
		const WireSegment&					segment,
		uint32											where);
	
	// redraw a wire (immediately or later, depending on the
	// value of m_bDeferSegmentRedraw)
	void touchWire(
		Wire*												wire);
	
	// redraw a single wire segment (immediately or later, depending on the
	// value of m_bDeferSegmentRedraw)
	void touchSegment(
		const WireSegment&					segment);
	
	// redraw all deferred segments
	void redrawTouchedSegments();

	// get BPoint for wire vertex
	// (in container-view coordinates)
	BPoint vertexToPoint(
		const WireVertex&						v) const;
		
	// figure bounds rectangle for the given wire segment
	// (in container-view coordinates)
	BRect segmentToRect(
		const WireSegment&					segment) const;
	
	// returns false if the given subset of a grid row is blocked
	// by a cell, or true if it's free.  (checks from 'fromColumn'
	// up to and including 'toColumn')
	bool gridRowSubsetClear(
		uint32											row,
		uint32											fromColumn,
		uint32											toColumn);

private:												// impl. members

	// the container view, which is responsible for:
	// - drawing gutter rows and columns
	// - drawing empty slots
	// - acting as the GridView container (storing live-node cells)
	MediaRoutingContainerView*		m_containerView;
	
	// the map of node ID -> position in grid
	typedef pair<uint32, uint32> column_row_pair;
	typedef map<media_node_id, column_row_pair> node_location_map;

	node_location_map			m_nodeLocationMap;

	// the map in which all visible Wire instances are stored; wires are
	// mapped by unique ID of the Connection they represent.

	typedef map<uint32, Wire*> wire_map;
	wire_map								m_wireMap;
	
	// the buffer in which displaced wires are stored during a
	// grid operation.  any operation that adds/removes cells, rows, or
	// columns may cause one or more wires to need re-routing.  those
	// wires are referenced in m_displacedWires, and after the operation
	// is complete routeWire() is called on each to update the segment
	// sets.
	
	typedef set<Wire*> wire_set;
	wire_set							m_displacedWires;
	
	// the set of wire segments touched (added or removed by) a grid
	// operation; the areas they span need to be redrawn.
	
	// [e.moon 13oct99] now a set of <WireSegment*>, to mollify the
	// PPC compiler
//	typedef set<WireSegment>		segment_set;
	typedef set<const WireSegment*>		segment_set;
	segment_set						m_touchedSegments;
	
	// operation mode (update segments instantly or defer) ?
	bool									m_bDeferSegmentRedraw;

	// default wire-vector size
	static const int			s_wireVectorCapacity = 16;

// removed 11aug99
//private:												// transports
//	Transport*					m_pAudioInputTransport;
//	Transport*					m_pAudioMixerTransport;
//	Transport*					m_pVideoOutputTransport;
//

private:												// cell selection state
	LiveNodeView*					m_selectedCell;
	vector<Wire*>					m_selectedWires;

private:												// external drag operation state
	// media node successfully dropped (instantiated)
	NodeRef*							m_extDroppedNode;
	
	// location of dropped node
	BPoint								m_extDropPoint;

private:												// internal drag operation state

	// The cell that initiated/is managing the drag operation
	// (also the cell being moved, when performing DRAG_CELL)
	// If 0, no drag operation is in progress.

	LiveNodeView*					m_dragCell;

	// previous position of dragged cell
	uint32								m_dragCellRow;
	uint32								m_dragCellColumn;	
	
	// offset from mouse position to top left corner of cell
	// frame rectangle (this should always be negative, in other
	// words)
	BPoint								m_dragOffset;

	// when dragging a multi-slot cell, this tracks which row
	// the user originally clicked on
	uint32								m_dragCellRowOffset;
	
	// height of dragged cell
	uint32								m_dragCellRowSpan;
	
	// * DRAG_WIRE-specific state data
	
	// the jack (connection point) at which the user started
	// the gesture
	WireVertex*						m_dragFromVertex;
	
	// the jack (connection point) to which the user has dragged
	// a connection-to-be (may be 0 if the mouse isn't currently
	// over a viable jack.)
	WireVertex*						m_dragToVertex;
	
	// pulse timer for jack-drag animation (blinking icons on
	// origin & target jacks)

	int16									m_dragVertexFlashTimer;
	static const int16		s_dragVertexFlashPeriod		= 1;
	bool									m_dragVertexFlashOn;
	bool									m_dragVertexFlashState;
	
	// +++++

	// current new-group-name index
	uint32										m_nextGroupNumber;

public:												// display stuff

	// current cell-view font
	BFont											m_cellFont;
	
	// animation rate
	static const bigtime_t		s_pulseRate = 50000LL;
	
	static const rgb_color		s_wireColor;
	static const rgb_color		s_selectedWireColor;
	static const rgb_color		s_jackOutlineColor;
	static const rgb_color		s_workspaceColor;
	
	// +++++

public:												// display defaults & constants

	static const uint32				s_defNodeRows					= 8;
	static const uint32				s_defNodeColumns			= 5;
};

__END_CORTEX_NAMESPACE
#endif /* __MEDIAROUTINGVIEW__H__ */
