module yamalib.gui.guislidebar;

private import y4d_draw.texture;
private import y4d_draw.drawbase;
private import y4d_draw.screen;
private import y4d_input.mouse;
private import y4d_input.keyinputbase;

private import yamalib.gui.guiparts;


/**
	GUIのスライダークラス
*/
class Slidebar : IGUIParts {
	
	/// スクロールバーのサイズ
	void setSize(int x_, int y_) {
		this.m_sx = x_;
		this.m_sy = y_;
	}
	
	/// キーを設定する
	void setKey(KeyInputBase key_) {
		this.m_key = key_;
	}
	
	/// スライドバーが動かされたか
	bool isModifiy() {
		return cast(bool) (m_posOld != m_pos);
	}
	
	/// スライダーの可動範囲の設定
	void setLength( int length_ ) {
		this.m_length = length_;
	}
	/// スライダーの可動範囲の取得
	int getLength() {
		return this.m_length;
	}
	
	/// 位置の設定
	override void setXY(int x_, int y_) {
		super.setXY(x_,y_);
	}
	
	/// スライダーボタンのオフセット位置
	void setSliderOffset(int ox_, int oy_){
		this.m_ox = ox_;
		this.m_oy = cast(int) (oy_ - m_barTex.getHeight() / 2);
	}

	/// スライド位置の設定
	void setSlidePos( float f ) {
		if ( 1.0f < f ) {
			f = 1.0f;
		} else if (0.0f > f) {
			f = 0.0f;
		}
		this.m_pos = cast(int) (m_length * f) + x;
	}
	/// スクロールポジションの取得(0 - 1.0)
	float getSlidePos() {
		int width = m_pos - x;
		if (width == 0) {
			return 0.0f;
		}
		return width / cast(float) m_length;
	}
	
	
	/// 下地テクスチャの設定
	void setBaseTexture(Texture t_) {
		this.m_baseTex = t_;
	}
	
	/// バーテクスチャの設定
	void setBarTexture(Texture t_) {
		this.m_barTex = t_;
		m_texSz = cast(int) t_.getWidth();
		this.m_sx = cast(int) t_.getWidth();
		this.m_sy = cast(int) t_.getHeight();
	}
	
	/// 毎回呼び出すなり
	override void onMove(Screen screen) {
		int mx,my;
		mouse.getPos(mx,my);
		m_posOld = m_pos;
		
		// key対応
		if ( !(m_key is null) ) {
			bool isIn = ptInRect( mx, my, m_pos+m_ox, y+m_oy, m_pos+m_sx+m_ox, y+m_sy+m_oy );

			// キーフォーカスされているときに、マウスが操作されたら、キーフォーカスをOFFにする
			if  (m_keyFocused && m_keyFocusedMove) {
				if (mx != preMx || my != preMy) {
					m_keyFocused = false;
				}
			}

			if (!isIn || !m_keyFocused) {
				this.m_keyFocused = false;
				this.m_keyFocusedMove = false;
				onMoveSlider(mouse.isPress(MouseInput.button.left), mx, my);
			} else {
				if ( m_key.isPress(3) ) {
					// 左
					if (!isMin()) {
						mx -= KEY_MOVE_SIZE;
					}
					
				} else if ( m_key.isPress(4)) {
					// 右
					if (!isMax()) {
						mx += KEY_MOVE_SIZE;
					}
				}
				mouse.setPos(mx,my);
				preMx = mx;
				preMy = my;
				m_keyFocusedMove = true;
				onMoveSlider(true, mx, my);
			}


		} else {
			// キーは設定されていない
			onMoveSlider(mouse.isPress(MouseInput.button.left), mx, my);
		}
	}
	
	/// スライダーの移動動作
	void onMoveSlider(bool leftDown, int mouseX, int mouseY) {
		if ( m_pos < this.x ) {
			m_pos = this.x;
		}
		
		if ( leftDown ) {
			// キャッチしていない時に、スライドバー自体をキャッチした
			if ( 0==m_catch  
				&& ptInRect( mouseX, mouseY, m_pos+m_ox, y+m_oy, m_pos+m_sx+m_ox, y+m_sy+m_oy ) ) {
				m_catch = 1;
				m_catchOx = m_pos - mouseX;
			}
			
			// キャッチしてないときに、スライドバー可動範囲のどこかを選択した
			else if ( 0==m_catch 
				&& ptInRect( mouseX, mouseY, x, y+m_oy, x + m_sx + m_length, y + m_sy+m_oy ) ) {
				m_catch = 2;
				m_catchOx = 0;
			}
		} else {
			m_catch = 0;
		}
		
		// キャッチしている
		if ( m_catch != 0 ) {
			m_pos = mouseX + m_catchOx;
			if ( m_pos < this.x ) {
				m_pos = this.x;
			} else if ( m_pos > this.x + m_length ) {
				m_pos = this.x + m_length;
			}
		}
	}
	
	/// 毎回呼び出す名なり
	override void onDraw(Screen screen) {
		Color4ub colorOrg = screen.getColor4ub();
		
		// 下地描画
		screen.blt( this.m_baseTex, x, y);
		
		// スライダー描画
		if ( m_barTex is null ) {
			screen.setColor(0,255,0);
			screen.drawPolygon(
				x+m_ox,			m_pos,
				x+m_oy,			m_pos+m_texSz,
				x+m_ox+m_sx,	m_pos+m_texSz,
				x+m_oy+m_sx,	m_pos
			);
		} else {
			// テクスチャとして描画
			screen.blt( this.m_barTex, m_pos + m_ox, y + m_oy );
		}
		
		// 色戻し
		screen.setColor( colorOrg );
	}
	
	/// キーフォーカス状態の設定	
	void setKeyFocus(bool b) {
		m_keyFocused = b;
	}
	
	/// フォーカス処理を実装する
	override void focus() 
	in 
	{
		// プロトタイプだけ作るのは、バグの温床
		assert( !(this.mouse is null) );
		assert( !(this.m_barTex is null) );
	}
	body
	{
		int mx = m_pos + m_ox + cast(int) m_barTex.getWidth() / 2;
		int my = y + m_oy + cast(int) m_barTex.getHeight() / 2;
		mouse.setPos(mx, my);
		m_keyFocused = true;
	}
	
	/// スライダーバーの中にあるか？
	bool isIn() {
		int mx,my;
		mouse.getPos(mx,my);
		return isCursorInButton(mx,my);
	}
	
	/// スライダーバーが最大になっているか？
	bool isMax() {
		return getSlidePos() == 1.0f;
	}
	
	/// スライダーが最低になっているか？
	bool isMin() {
		return getSlidePos() == 0.0f;
	}
	
	
private:
	/// 点が矩形の内側にあるかどうか
	static bool ptInRect(int px, int py, int left, int top, int right, int bottom) {
		return cast(bool) (px >= left && px < right
			&& py >= top && py < bottom);
	}
	
	static const int LC_SCROLL_MAX = 65535;
	
	/// 引数で指定した座標はスライダーボタンの中にあるか？
	bool isCursorInButton(int mouseX, int mouseY) {
		return ptInRect( mouseX, mouseY, x, y+m_oy, x + m_sx + m_length, y + m_sy+m_oy );
	}
	
	static const int KEY_MOVE_SIZE = 3;
	

	Texture m_barTex;	// スライダーボタンのテクスチャ
	Texture m_baseTex;	// 下地となるテクスチャ
	
	KeyInputBase m_key;
	
	bool m_keyFocused;
	bool m_keyFocusedMove;

	int m_posOld;	//!< 前の位置	
	int preMx;
	int preMy;
	
	int m_texSz;
	int m_ox;
	int m_oy;
	int m_sx;		//!< スライダーボタンの大きさ
	int m_sy;
	int m_length;	//!< スライダーの可動範囲
	int m_pos;		//!< 現在のスクロールバーの位置
	int m_catch;	//!< スクロールバーをつかんでいるか
	int m_catchOx;

}