// GridView.h (cortex)
// 8mar99 - begun (looper)

// ************************************************************************
// An extensible grid-based 'layout manager': a container
// BView supporting multiple rows & columns with adjustable
// scrolling & resizing.
// ************************************************************************

// ************************************************************************
//
// 17may99:
// - implemented canAddCell()
//
// 14may99:
// - adding a 'scroll fudge factor' -- the setScrollMargins() call
//   lets you tweak the scroll-bar sizing (by subtracting the given
//   offsets from the real data bounds)
//
// 10may99:
// ! cell resizing: adding very basic support -- cells may be
//   resized (ie. row- and column-span may be changed after they're
//   added) but they may not overlap other cells.
//
// 7may99: NEEDS
// ! extend error handling: either define some GridView-specific error
//   messages, or use exceptions.
// 6may99
// ? should there be resize-handle support at this level?
// * added createContainerView() hook
//
// 5may99: OVERHAUL:
// * moved GridRow and GridColumn to separate files
// * store pointers rather than instances in row and column vectors
// * removed all workspace-related stuff from the API:
//   - top/bottom-most rows
//   - scroll-target column
// * added hooks for nested container view(s):
//   - containerView()
//   - frameView()
// * removed locking
//
//
// ************************************************************************


// [original] Implementation notes
// e.moon 8mar99
//
// Separate row and column vectors store layout info for each
// row and column.  An additional cell vector within each row
// stores actual cell entries (pointer to cell view & column-span).
// This makes adding rows relatively cheap, and adding columns
// relatively expensive.  It might be handy to make columns
// 'collapsable': that is, hide their cells without removing/
// reorganizing the layout structures.


#ifndef __GridView_H__
#define __GridView_H__
//#include "defs.h"

#include <vector>

#include <View.h>
#include <ScrollBar.h>

//#include "MouseTrackingHelpers.h"
#include "ScrollHelpers.h"

class BScrollView;

#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE


class RowGripView;

class GridRow;
class GridColumn;

// ---------------------------------------------------------------- //
// GridView
// ---------------------------------------------------------------- //

class GridView :
	public BView {

	typedef BView _inherited;

public:										// constants
	// +++++ flags
	enum layout_flag_t {
		NONE,
		ROWS_RESIZABLE						=1,		// row-size grip provided
		ROWS_RESIZE_IN_TANDEM			=2		// rows are 'ganged' in size
	};
	
public:										// HOOKS
	// e.moon 6may99
	// returns the top-level frame view (the container view is expected
	// to be a direct child of this view.)  by default, this is the
	// GridView itself; subclasses may want to augment the GridView and
	// make only a portion of it scrollable
	virtual BView* frameView();

/*	
	// e.moon 6may99
	// create a BView or subclass to serve as the container for
	// scrollable cells.  the frame rectangle is managed by the GridView,
	// so setting it to (0,0,0,0) works fine.
	// default implementation: returns a stock BView
	virtual BView* createContainerView();
*/

public:										// ctor/dtor
	GridView(BRect frame, const char* pName,
		int32 resizeMode, int32 viewFlags, int32 layoutFlags);

	~GridView();

public:										// diagnostics 11may99
	void dumpStructure();
	
public:										// row/column/cell access

	// Column access
	GridColumn* columnFor(int32 type) const;
	// returns -1 if not found:
	int32 columnIndexFor(int32 type) const;
	// returns -1 if not found; xPos is 
	int32 columnIndexFor(float xPos) const;
	int32 columns() const;
	GridColumn* columnAt(int32 index) const;
	
	// Row access
	int32 rows() const;
	GridRow* rowAt(uint32 row) const;
	int32 rowIndexFor(float yPos) const;

	// Row resizing
	// +++++ yer days are numbered
	float rowResizeStep() const;
	status_t setRowResizeStep(float fStep);

	// Cell access:
	// looks for a cell in or overlapping the given column and row.
	// returns true if a cell was found, as well as a pointer to the
	// view and the real origin (top/left row and column) and size
	// of the cell.

	bool getCell(
		uint32 column, uint32 row,
		BView** poCellView,
		uint32* poOriginColumn, uint32* poOriginRow,
		uint32* poColumnSpan, uint32* poRowSpan) const;
	
	// as above, but looks at a point

	bool getCell(
		BPoint where,
		BView** poCellView,
		uint32* poOriginColumn, uint32* poOriginRow,
		uint32* poColumnSpan, uint32* poRowSpan) const;
		
	// as above, but fails if the cell's origin isn't in the
	// provided row and column
	// [13may99]: poColumnSpan and poRowSpan are optional

	bool getCell(
		uint32 column, uint32 row,
		BView** poCellView,
		uint32* poColumnSpan=0, uint32* poRowSpan=0) const;

	// as above (matches only a cell with the given origin
	// row/column)
	bool findCell(
		uint32 column, uint32 row) const;

public:										// operations

	// COLUMN MANAGEMENT

	// takes ownership of pColumn
	status_t addColumn(uint32 atIndex, GridColumn* pColumn);

	status_t addColumn(uint32 atIndex, float width);
	status_t addColumn(uint32 atIndex, float width, uint32 id);
		
	status_t deleteColumn(uint32 atIndex);
		
	status_t moveColumn(uint32 fromIndex, uint32 toIndex); //nyi
	
	// ROW MANAGEMENT
	
	status_t addRow(uint32 atIndex, GridRow* pRow);
	status_t addRow(uint32 atIndex, float height);
	status_t addRows(uint32 atIndex, float height, uint32 count);

	status_t deleteRow(uint32 atIndex);
		
	status_t moveRow(uint32 fromIndex, uint32 toIndex); //nyi

	// CELL MANAGEMENT

	status_t addCell(BView* pCellView,
		uint32 columnIndex, uint32 rowIndex,
		uint32 columnSpan=1, uint32 rowSpan=1);
		
	bool canAddCell(
		uint32 columnIndex, uint32 rowIndex,
		uint32 columnSpan=1, uint32 rowSpan=1); //nyi
	
	BView* removeCell(uint32 columnIndex, uint32 rowIndex);
	
	status_t resizeCell(
		uint32 columnIndex, uint32 rowIndex,
		uint32 columnSpan, uint32 rowSpan);
		
	// DATA-BOUNDS/SCROLLING
	
	void setScrollMargins(float width, float height);
	void getScrollMargins(float* poWidth, float* poHeight);
	
/* removed 11may99 e.moon
public:										// IMouseTrackingDestination impl.

	// a MouseTrackingSourceView has started tracking the mouse
	// (point is in screen coordinates)
	virtual void mouseTrackingBegin(
		MouseTrackingSourceView* pSource,
		uint32 buttons,
		BPoint point); //nyi
	
	// mouse-tracking update from child view
	// (point is in screen coordinates)
	virtual void mouseTrackingUpdate(
		uint32 buttons,
		float xDelta,
		float yDelta,
		BPoint point); //nyi
	
	// mouse-tracking done
	virtual void mouseTrackingEnd(); //nyi
*/
public:										// BView implementation

	// trigger extra layout once attached to window
	virtual void AttachedToWindow();
	virtual void AllAttached();
	
	// handle resize
	virtual void FrameResized(float width, float height);
	
	virtual void TargetedByScrollView(BScrollView* pScroller);
	
protected:									// impl. operations

	// removes the entry for a cell view without removing the
	// child view itself from the hierarchy.  called by
	// removeCell().  be careful with this one!
	BView* removeCellEntry(uint32 columnIndex, uint32 rowIndex);

	// moves cells in a given range of columns (including begin,
	// excluding end) horizontally by provided offset.  Updates
	// column offset values to match.
	void offsetColumns(uint32 begin, uint32 end, float xOffset);
		
	// moves cells in given range of rows (including begin, excluding
	// end) vertically by given offset.  Update srow offset values to
	// match.
	void offsetRows(uint32 begin, uint32 end, float yOffset);

	// resizes the given column, and all cells in/overlapping it.
	// set bOffsetFollowing to false to suppress repositioning of
	// following columns.
	void resizeColumn(uint32 column, float width,
		bool bOffsetFollowing=true);
	
	// resizes the given scrollable row (or all scrollable rows, if ganged)
	// constrains the given height to sane limits
	// +++++ broken: needs row-span support -- 5may99 e.moon
	//       also needs to support non-scrollable rows
	// set bOffsetFollowing to false to suppress repositioning of
	// following rows.
	
	void resizeRow(uint32 row, float height,
		bool bOffsetFollowing=true); //nyi
	
	// initialize the given column
	void initColumn(GridColumn* pColumn, uint32 destIndex);
	
	// initialize the given row (set position & any other layout
	// settings)
	void initRow(GridRow* pRow, int32 destIndex);
	
	// access the child view in which the cells are stored
	BView* containerView() { return m_pContainerView; }
	
	// replace the cell-storage view with a new BView object.
	// existing cells are moved to the new view.
	void setContainerView(BView* pView);

	// refigure total grid width & height and resize the container
	// view appropriately
	void updateDataBounds();

	// recalculate scroll limits based on frame and container view sizes
	void updateScrollLimits();
	
private:										// guts
	void initContainerView();

private:										// impl. member types
	typedef vector<GridRow*> row_vector;
	typedef vector<GridColumn*> column_vector;
	
private:										// ROW/COLUMN STRUCTURE

	// the set of rows
	row_vector				m_rows;

	// the set of columns
	column_vector			m_columns;

	// layout settings
	uint32						m_layoutFlags;

private:										// PRESENTATION

	// the cell-container view
	BView*						m_pContainerView;
	
	// scroller view
	BScrollView*			m_pScrollView;
	float							m_scrollMarginWidth;
	float							m_scrollMarginHeight;

	// cached frame rectangle
	BRect							m_curFrame;

	// current row being resized (-1 if no resize operation active)
	int32							m_resizeRow;
	float							m_fResizeRowHeight;

	// increment by which rows are resized
	float										m_fRowResizeStep;
	static const float				s_fDefRowResizeStep;



	// +++++ deprecated & icky	
	// current 'ganged' row size
	// (will be initialized to the size of the first scrollable
	//  row added.)
	float										m_fGangedRowHeight;
	static const float				s_fDefRowHeight;
	
	static const float				s_fMinRowHeight;
	static const float				s_fMaxRowHeight;

	// thickness of row/column resize grips 
	static const float				s_fGripSize;
};

__END_CORTEX_NAMESPACE
#endif /* __GridView_H__ */
