package Roguelike.UI; import Roguelike.AssetManager; import Roguelike.Global; import Roguelike.Screens.GameScreen; import Roguelike.Sprite.Sprite; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.NinePatch; import com.badlogic.gdx.input.GestureDetector; import com.badlogic.gdx.input.GestureDetector.GestureListener; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.Widget; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Pools; public abstract class TilePanel extends Widget { private final TilePanel thisRef = this; protected int tileSize; protected int targetWidth; protected int targetHeight; protected int viewWidth; protected int viewHeight; protected int dataWidth; protected int dataHeight; protected int scrollX; protected int scrollY; protected final Skin skin; protected final Stage stage; public int padding = 10; public boolean canBeExamined = true; protected NinePatch tilePanelBackgroundH; protected NinePatch tilePanelBackgroundV; protected boolean drawHorizontalBackground = true; protected Sprite tileBackground; protected Sprite tileBorder; protected Array<Object> tileData = new Array<Object>(); protected Object mouseOver; protected boolean expandVertically; public TilePanel( Skin skin, Stage stage, Sprite tileBackground, Sprite tileBorder, int viewWidth, int viewHeight, int tileSize, boolean expandVertically ) { this.skin = skin; this.stage = stage; this.tileBackground = tileBackground; this.tileBorder = tileBorder; this.targetWidth = viewWidth; this.targetHeight = viewHeight; this.viewWidth = viewWidth; this.viewHeight = viewHeight; this.tileSize = tileSize; this.expandVertically = expandVertically; this.tilePanelBackgroundH = new NinePatch( AssetManager.loadTextureRegion( "Sprites/GUI/PanelHorizontal.png" ), 21, 21, 21, 21 ); this.tilePanelBackgroundV = new NinePatch( AssetManager.loadTextureRegion( "Sprites/GUI/PanelVertical.png" ), 21, 21, 21, 21 ); TilePanelListener listener = new TilePanelListener(); this.addListener( listener ); this.setWidth( getPrefWidth() ); } public abstract void populateTileData(); public abstract Sprite getSpriteForData( Object data ); public abstract void handleDataClicked( Object data, InputEvent event, float x, float y ); public abstract Table getToolTipForData( Object data ); public abstract Color getColourForData( Object data ); public abstract void onDrawItemBackground( Object data, Batch batch, int x, int y, int width, int height ); public abstract void onDrawItem( Object data, Batch batch, int x, int y, int width, int height ); public abstract void onDrawItemForeground( Object data, Batch batch, int x, int y, int width, int height ); public boolean isPointInThis( int x, int y ) { Vector2 vec2 = Pools.obtain(Vector2.class).set( x, y ); vec2 = this.screenToLocalCoordinates( vec2 ); if ( vec2.x >= 0 && vec2.y >= 0 && vec2.x <= getWidth() && vec2.y <= getHeight() ) { Pools.free( vec2 ); return true; } Pools.free( vec2 ); return false; } @Override public void invalidate() { super.invalidate(); if ( expandVertically ) { viewHeight = (int) ( ( getHeight() - padding ) / ( tileSize + padding ) ); } } @Override public float getMinWidth() { return ( tileSize + padding ) * targetWidth + padding; } @Override public float getMinHeight() { return ( tileSize + padding ) * targetHeight + padding; } private void validateScroll() { int scrollableX = Math.max( 0, dataWidth - viewWidth ); int scrollableY = Math.max( 0, dataHeight - viewHeight ); scrollX = MathUtils.clamp( scrollX, 0, scrollableX ); scrollY = MathUtils.clamp( scrollY, 0, scrollableY ); } @Override public void draw( Batch batch, float parentAlpha ) { populateTileData(); validateScroll(); int height = viewHeight * ( tileSize + padding ) + padding; int width = viewWidth * ( tileSize + padding ) + padding; if ( dataHeight > viewHeight ) { width += 25; } batch.setColor( Color.WHITE ); if (drawHorizontalBackground) { tilePanelBackgroundH.draw( batch, getX(), getY() + getHeight() - height, width, height ); } else { tilePanelBackgroundV.draw( batch, getX(), getY() + getHeight() - height, width, height ); } int xOffset = (int) getX() + padding; int top = (int) ( getY() - padding + getHeight() ) - tileSize; if ( dataHeight > viewHeight ) { tileBackground.render( batch, xOffset + tileSize + 5, top - height, 10, height ); } int x = 0; int y = 0; batch.setColor( Color.DARK_GRAY ); for ( y = 0; y < viewHeight; y++ ) { for ( x = 0; x < viewWidth; x++ ) { if ( tileBackground != null ) { tileBackground.render( batch, x * ( tileSize + padding ) + xOffset, top - y * ( tileSize + padding ), tileSize, tileSize ); } } } x = 0; y = 0; int scrollOffset = scrollY * viewWidth + scrollX; for ( int i = scrollOffset; i < tileData.size; i++ ) { Object item = tileData.get( i ); Color baseColour = item != null && item == mouseOver ? Color.WHITE : Color.LIGHT_GRAY; Color itemColour = getColourForData( item ); if ( itemColour != null ) { itemColour = new Color( baseColour ).mul( itemColour ); } else { itemColour = baseColour; } batch.setColor( itemColour ); if ( tileBackground != null ) { tileBackground.render( batch, x * ( tileSize + padding ) + xOffset, top - y * ( tileSize + padding ), tileSize, tileSize ); } onDrawItemBackground( item, batch, x * ( tileSize + padding ) + xOffset, top - y * ( tileSize + padding ), tileSize, tileSize ); batch.setColor( Color.WHITE ); Sprite sprite = getSpriteForData( item ); if ( sprite != null ) { sprite.render( batch, x * ( tileSize + padding ) + xOffset, top - y * ( tileSize + padding ), tileSize, tileSize ); } onDrawItem( item, batch, x * ( tileSize + padding ) + xOffset, top - y * ( tileSize + padding ), tileSize, tileSize ); batch.setColor( itemColour ); if ( tileBorder != null && item != null ) { tileBorder.render( batch, x * ( tileSize + padding ) + xOffset, top - y * ( tileSize + padding ), tileSize, tileSize ); } onDrawItemForeground( item, batch, x * ( tileSize + padding ) + xOffset, top - y * ( tileSize + padding ), tileSize, tileSize ); x++; if ( x == viewWidth ) { x = 0; y++; if ( y == viewHeight ) { break; } } } } public class TilePanelListener extends InputListener { boolean longPressed = false; boolean dragged = false; float dragX; float dragY; float lastX; float lastY; private Object pointToItem( float x, float y ) { if ( x < padding || y < padding || x > getWidth() - padding || y > getHeight() - padding ) { return null; } y = getHeight() - y; int xIndex = (int) ( ( x - padding ) / ( tileSize + padding ) ); int yIndex = (int) ( ( y - padding ) / ( tileSize + padding ) ); if ( xIndex >= viewWidth || yIndex >= viewHeight ) { return null; } int xpos = (int) ( x - ( tileSize + padding ) * xIndex ); int ypos = (int) ( y - ( tileSize + padding ) * yIndex ); if ( xpos > tileSize + padding || ypos > tileSize + padding ) { return null; } xIndex += scrollX; yIndex += scrollY; int index = yIndex * viewWidth + xIndex; if ( index >= tileData.size || index < 0 ) { return null; } return tileData.get( index ); } @Override public void touchDragged( InputEvent event, float x, float y, int pointer ) { if ( !dragged && ( Math.abs( x - dragX ) > 10 || Math.abs( y - dragY ) > 10 ) ) { dragged = true; lastX = x; lastY = y; } if ( dragged ) { int xdiff = (int) ( ( x - lastX ) / tileSize ); int ydiff = (int) ( ( y - lastY ) / tileSize ); if ( xdiff != 0 ) { scrollX -= xdiff; lastX = x; } if ( ydiff != 0 ) { scrollY += ydiff; lastY = y; } } } @Override public boolean scrolled( InputEvent event, float x, float y, int amount ) { if ( dataWidth > viewWidth ) { scrollX += amount; } else { scrollY += amount; } return true; } @Override public boolean mouseMoved( InputEvent event, float x, float y ) { if ( Tooltip.openTooltip != null ) { Tooltip.openTooltip.setVisible( false ); Tooltip.openTooltip.remove(); Tooltip.openTooltip = null; } Object item = pointToItem( x, y ); if ( item != null ) { Table table = getToolTipForData( item ); if ( table != null ) { Tooltip tooltip = new Tooltip( table, skin, stage ); tooltip.show( event, x, y, false ); } } mouseOver = item; stage.setScrollFocus( thisRef ); return true; } @Override public boolean touchDown( InputEvent event, float x, float y, int pointer, int button ) { if ( Tooltip.openTooltip != null ) { Tooltip.openTooltip.setVisible( false ); Tooltip.openTooltip.remove(); Tooltip.openTooltip.openTooltip.openTooltip = null; Tooltip.openTooltip = null; } GameScreen.Instance.clearContextMenu( false ); GameScreen.Instance.addTouchAction( event.getStageX(), event.getStageY() ); dragged = false; dragX = x; dragY = y; return true; } @Override public void touchUp( InputEvent event, float x, float y, int pointer, int button ) { if ( Tooltip.openTooltip != null ) { Tooltip.openTooltip.setVisible( false ); Tooltip.openTooltip.remove(); Tooltip.openTooltip = null; } GameScreen.Instance.clearContextMenu( false ); Object item = pointToItem( x, y ); if ( !longPressed && !dragged && item != null ) { if ( canBeExamined && GameScreen.Instance.examineMode ) { Table table = getToolTipForData( item ); if ( table != null ) { Tooltip tooltip = new Tooltip( table, skin, stage ); tooltip.show( event, x, y, false ); } } else { handleDataClicked( item, event, x, y ); } } dragged = false; } @Override public void enter( InputEvent event, float x, float y, int pointer, Actor toActor ) { stage.setScrollFocus( thisRef ); } @Override public void exit( InputEvent event, float x, float y, int pointer, Actor toActor ) { mouseOver = null; if ( Tooltip.openTooltip != null ) { Tooltip.openTooltip.setVisible( false ); Tooltip.openTooltip.remove(); Tooltip.openTooltip.openTooltip.openTooltip = null; Tooltip.openTooltip = null; } GameScreen.Instance.mouseOverUI = false; } } }