2018-09-02 13:36:49 +02:00
package it.cavallium.warppi.gui.expression.blocks ;
2017-03-03 23:06:43 +01:00
2018-09-04 12:12:41 +02:00
import it.cavallium.warppi.Engine ;
2018-09-02 13:36:49 +02:00
import it.cavallium.warppi.gui.GraphicalElement ;
import it.cavallium.warppi.gui.expression.Caret ;
import it.cavallium.warppi.gui.expression.CaretState ;
import it.cavallium.warppi.gui.graphicengine.BinaryFont ;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine ;
import it.cavallium.warppi.gui.graphicengine.Renderer ;
import it.cavallium.warppi.math.Function ;
import it.cavallium.warppi.math.MathContext ;
import it.cavallium.warppi.math.parser.MathParser ;
import it.cavallium.warppi.math.parser.features.interfaces.Feature ;
2018-09-12 22:16:33 +02:00
import it.cavallium.warppi.util.Error ;
import it.cavallium.warppi.util.Errors ;
2017-05-16 22:02:44 +02:00
import it.unimi.dsi.fastutil.objects.ObjectArrayList ;
2017-03-03 23:06:43 +01:00
public class BlockContainer implements GraphicalElement {
2017-03-26 22:44:09 +02:00
private static boolean initialized = false ;
2017-04-10 22:50:43 +02:00
2017-04-11 22:04:44 +02:00
private int minWidth ;
private int minHeight ;
2017-03-03 23:06:43 +01:00
private final ObjectArrayList < Block > content ;
private boolean small ;
private int width ;
private int height ;
private int line ;
2017-03-26 22:44:09 +02:00
public final boolean withBorder ;
2017-04-11 22:04:44 +02:00
private boolean autoMinimums ;
2017-04-10 22:50:43 +02:00
2017-03-03 23:06:43 +01:00
public BlockContainer ( ) {
2017-03-26 22:44:09 +02:00
this ( false , BlockContainer . getDefaultCharWidth ( false ) , BlockContainer . getDefaultCharHeight ( false ) , true ) ;
2017-04-11 22:04:44 +02:00
autoMinimums = true ;
2017-03-03 23:06:43 +01:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public BlockContainer ( final boolean small ) {
2017-03-26 22:44:09 +02:00
this ( small , BlockContainer . getDefaultCharWidth ( small ) , BlockContainer . getDefaultCharHeight ( small ) , true ) ;
2017-04-11 22:04:44 +02:00
autoMinimums = true ;
2017-03-26 22:44:09 +02:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public BlockContainer ( final boolean small , final ObjectArrayList < Block > content ) {
2017-11-01 22:34:35 +01:00
this ( small , BlockContainer . getDefaultCharWidth ( small ) , BlockContainer . getDefaultCharHeight ( small ) , content , true ) ;
autoMinimums = true ;
}
2018-09-22 11:17:30 +02:00
public BlockContainer ( final boolean small , final boolean withBorder ) {
2017-03-26 22:44:09 +02:00
this ( small , BlockContainer . getDefaultCharWidth ( small ) , BlockContainer . getDefaultCharHeight ( small ) , withBorder ) ;
2017-04-11 22:04:44 +02:00
autoMinimums = true ;
2017-03-03 23:06:43 +01:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public BlockContainer ( final boolean small , final int minWidth , final int minHeight , final boolean withBorder ) {
2017-03-26 22:44:09 +02:00
this ( small , minWidth , minHeight , new ObjectArrayList < > ( ) , withBorder ) ;
2017-04-11 22:04:44 +02:00
autoMinimums = false ;
2017-03-03 23:06:43 +01:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public BlockContainer ( final boolean small , final int minWidth , final int minHeight , final ObjectArrayList < Block > content , final boolean withBorder ) {
2017-03-03 23:06:43 +01:00
this . small = small ;
this . minWidth = minWidth ;
this . minHeight = minHeight ;
2017-03-26 22:44:09 +02:00
this . withBorder = withBorder ;
2018-09-22 11:17:30 +02:00
for ( final Block b : content )
if ( b . isSmall ( ) ! = small )
2017-03-26 22:44:09 +02:00
b . setSmall ( small ) ;
2017-03-03 23:06:43 +01:00
this . content = content ;
recomputeDimensions ( ) ;
}
2017-03-26 22:44:09 +02:00
2018-09-22 11:17:30 +02:00
public void addBlock ( final int position , final Block b ) {
2018-03-11 21:49:41 +01:00
addBlockUnsafe ( position , b ) ;
recomputeDimensions ( ) ;
}
2018-05-12 21:18:29 +02:00
2018-09-22 11:17:30 +02:00
public void addBlockUnsafe ( final int position , final Block b ) {
if ( b . isSmall ( ) ! = small )
2017-03-26 22:44:09 +02:00
b . setSmall ( small ) ;
2018-09-22 11:17:30 +02:00
if ( position > = content . size ( ) )
2017-03-26 22:44:09 +02:00
content . add ( b ) ;
2018-09-22 11:17:30 +02:00
else
2017-03-26 22:44:09 +02:00
content . add ( position , b ) ;
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public void appendBlock ( final Block b ) {
2017-04-10 22:50:43 +02:00
appendBlockUnsafe ( b ) ;
recomputeDimensions ( ) ;
}
2018-09-22 11:17:30 +02:00
public void appendBlockUnsafe ( final Block b ) {
if ( b . isSmall ( ) ! = small )
2017-03-26 22:44:09 +02:00
b . setSmall ( small ) ;
2017-03-03 23:06:43 +01:00
content . add ( b ) ;
}
2018-09-22 11:17:30 +02:00
public void removeBlock ( final Block b ) {
2018-03-11 21:49:41 +01:00
removeBlockUnsafe ( b ) ;
2017-03-03 23:06:43 +01:00
recomputeDimensions ( ) ;
}
2018-09-22 11:17:30 +02:00
public void removeBlockUnsafe ( final Block b ) {
2018-03-11 21:49:41 +01:00
content . remove ( b ) ;
}
2018-09-22 11:17:30 +02:00
public void removeAt ( final int i ) {
2017-03-03 23:06:43 +01:00
content . remove ( i ) ;
recomputeDimensions ( ) ;
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public BlockReference < ? > getBlockAt ( final int i ) {
2018-05-12 21:18:29 +02:00
final Block b = content . get ( i ) ;
2018-03-11 21:49:41 +01:00
return new BlockReference < > ( b , i , this ) ;
}
public int getSize ( ) {
return content . size ( ) ;
2017-03-03 23:06:43 +01:00
}
2017-04-10 22:50:43 +02:00
2017-03-03 23:06:43 +01:00
public void clear ( ) {
content . clear ( ) ;
recomputeDimensions ( ) ;
}
2017-04-10 22:50:43 +02:00
2017-03-03 23:06:43 +01:00
/ * *
2018-09-22 11:17:30 +02:00
*
2017-04-10 22:50:43 +02:00
* @param ge
* Graphic Engine class .
* @param r
* Graphic Renderer class of < b > ge < / b > .
* @param x
* Position relative to the window .
* @param y
* Position relative to the window .
* @param caret
* Position of the caret .
2017-03-03 23:06:43 +01:00
* /
2018-09-22 11:17:30 +02:00
public void draw ( final GraphicEngine ge , final Renderer r , final int x , final int y , final Caret caret ) {
2017-03-26 22:44:09 +02:00
int paddingX = 1 ;
2017-03-03 23:06:43 +01:00
2018-09-22 11:17:30 +02:00
if ( caret . getRemaining ( ) = = 0 )
if ( content . size ( ) > 0 )
2017-04-11 22:04:44 +02:00
BlockContainer . drawCaret ( ge , r , caret , small , x , y + line - content . get ( 0 ) . line , content . get ( 0 ) . height ) ;
2018-09-22 11:17:30 +02:00
else
2017-04-11 22:04:44 +02:00
BlockContainer . drawCaret ( ge , r , caret , small , x , y , height ) ;
2017-04-10 22:50:43 +02:00
2017-03-26 22:44:09 +02:00
if ( withBorder & & content . size ( ) = = 0 ) {
2017-05-05 22:27:11 +02:00
r . glColor ( BlockContainer . getDefaultColor ( ) ) ;
2017-04-10 22:50:43 +02:00
r . glDrawLine ( x + paddingX , y , x + paddingX + width - 1 , y ) ;
r . glDrawLine ( x + paddingX , y , x + paddingX , y + height - 1 ) ;
r . glDrawLine ( x + paddingX + width - 1 , y , x + paddingX + width - 1 , y + height - 1 ) ;
r . glDrawLine ( x + paddingX , y + height - 1 , x + paddingX + width - 1 , y + height - 1 ) ;
2018-09-22 11:17:30 +02:00
} else
2017-04-10 22:50:43 +02:00
for ( final Block b : content ) {
2017-03-26 22:44:09 +02:00
caret . skip ( 1 ) ;
2017-04-10 22:50:43 +02:00
b . draw ( ge , r , x + paddingX , y + line - b . line , caret ) ;
2017-03-26 22:44:09 +02:00
paddingX + = b . getWidth ( ) ;
2018-09-22 11:17:30 +02:00
if ( caret . getRemaining ( ) = = 0 )
2017-04-11 22:04:44 +02:00
BlockContainer . drawCaret ( ge , r , caret , small , x + paddingX , y + line - b . line , b . height ) ;
2017-03-26 22:44:09 +02:00
paddingX + = 1 ;
}
caret . skip ( 1 ) ;
}
2018-09-22 11:17:30 +02:00
public boolean putBlock ( final Caret caret , final Block newBlock ) {
2017-03-26 22:44:09 +02:00
boolean added = false ;
if ( caret . getRemaining ( ) = = 0 ) {
2017-04-10 22:50:43 +02:00
addBlock ( 0 , newBlock ) ;
2017-03-26 22:44:09 +02:00
added = true ;
}
2017-04-10 22:50:43 +02:00
2017-03-26 22:44:09 +02:00
int pos = 0 ;
2017-04-10 22:50:43 +02:00
for ( final Block b : content ) {
2017-03-26 22:44:09 +02:00
caret . skip ( 1 ) ;
pos + + ;
2017-04-10 22:50:43 +02:00
added = added | b . putBlock ( caret , newBlock ) ;
2017-03-26 22:44:09 +02:00
if ( caret . getRemaining ( ) = = 0 ) {
2017-04-10 22:50:43 +02:00
addBlock ( pos , newBlock ) ;
2017-03-26 22:44:09 +02:00
added = true ;
}
}
caret . skip ( 1 ) ;
2018-09-22 11:17:30 +02:00
if ( added )
2017-03-26 22:44:09 +02:00
recomputeDimensions ( ) ;
return added ;
}
2018-09-22 11:17:30 +02:00
public boolean delBlock ( final Caret caret ) {
2017-03-26 22:44:09 +02:00
boolean removed = false ;
2017-04-10 22:50:43 +02:00
2017-03-26 22:44:09 +02:00
int pos = 0 ;
2017-04-10 22:50:43 +02:00
for ( final Block b : content ) {
2017-03-03 23:06:43 +01:00
caret . skip ( 1 ) ;
2017-03-26 22:44:09 +02:00
pos + + ;
2017-04-10 22:50:43 +02:00
final int deltaCaret = caret . getRemaining ( ) ;
removed = removed | b . delBlock ( caret ) ;
2018-09-22 11:17:30 +02:00
if ( caret . getRemaining ( ) = = 0 | | removed = = false & & deltaCaret > = 0 & & caret . getRemaining ( ) < 0 ) {
2017-04-10 22:50:43 +02:00
removeAt ( pos - 1 ) ;
caret . setPosition ( caret . getPosition ( ) - deltaCaret ) ;
2017-03-26 22:44:09 +02:00
removed = true ;
}
2017-03-03 23:06:43 +01:00
}
caret . skip ( 1 ) ;
2018-09-22 11:17:30 +02:00
if ( removed )
2017-03-26 22:44:09 +02:00
recomputeDimensions ( ) ;
return removed ;
2017-03-03 23:06:43 +01:00
}
2018-09-22 11:17:30 +02:00
public BlockReference < ? > getBlock ( final Caret caret ) {
2018-03-11 21:49:41 +01:00
BlockReference < ? > block = null ;
2017-09-24 18:47:30 +02:00
2017-05-05 22:27:11 +02:00
int pos = 0 ;
for ( final Block b : content ) {
caret . skip ( 1 ) ;
pos + + ;
final int deltaCaret = caret . getRemaining ( ) ;
2017-09-24 18:47:30 +02:00
block = b . getBlock ( caret ) ;
2018-09-22 11:17:30 +02:00
if ( block ! = null )
2017-06-05 22:50:33 +02:00
return block ;
2018-09-22 11:17:30 +02:00
if ( caret . getRemaining ( ) = = 0 | | deltaCaret > = 0 & & caret . getRemaining ( ) < 0 ) {
2017-05-05 22:27:11 +02:00
block = getBlockAt ( pos - 1 ) ;
return block ;
}
}
caret . skip ( 1 ) ;
return block ;
}
2017-03-03 23:06:43 +01:00
@Override
public void recomputeDimensions ( ) {
int l = 0 ; //Line
int w = 0 ; //Width
int h2 = 0 ; //Height under the line. h = h2 + l
int h = 0 ; //Height
2017-04-10 22:50:43 +02:00
for ( final Block b : content ) {
2017-03-26 22:44:09 +02:00
w + = b . getWidth ( ) + 1 ;
2017-03-03 23:06:43 +01:00
final int bl = b . getLine ( ) ;
final int bh = b . getHeight ( ) ;
final int bh2 = bh - bl ;
2018-09-22 11:17:30 +02:00
if ( bl > l )
2017-03-03 23:06:43 +01:00
l = bl ;
2018-09-22 11:17:30 +02:00
if ( bh2 > h2 )
2017-03-03 23:06:43 +01:00
h2 = bh2 ;
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
if ( content . size ( ) > 0 )
2017-03-26 22:44:09 +02:00
w - = 1 ;
2017-04-10 22:50:43 +02:00
2017-03-03 23:06:43 +01:00
h = h2 + l ;
line = l ;
2018-09-22 11:17:30 +02:00
if ( w > minWidth )
2017-03-03 23:06:43 +01:00
width = w ;
2018-09-22 11:17:30 +02:00
else
2017-03-03 23:06:43 +01:00
width = minWidth ;
2018-09-22 11:17:30 +02:00
if ( h > minHeight )
2017-03-03 23:06:43 +01:00
height = h ;
2018-09-22 11:17:30 +02:00
else {
2017-03-03 23:06:43 +01:00
height = minHeight ;
2017-04-10 22:50:43 +02:00
line = height / 2 ;
2017-03-03 23:06:43 +01:00
}
}
@Override
public int getWidth ( ) {
return width ;
}
@Override
public int getHeight ( ) {
return height ;
}
@Override
public int getLine ( ) {
return line ;
}
private static final BinaryFont [ ] defFonts = new BinaryFont [ 2 ] ;
private static final int [ ] defFontSizes = new int [ 4 ] ;
private static final int defColor = 0xFF000000 ;
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public static void initializeFonts ( final BinaryFont big , final BinaryFont small ) {
BlockContainer . defFonts [ 0 ] = big ;
BlockContainer . defFonts [ 1 ] = small ;
BlockContainer . defFontSizes [ 0 ] = big . getCharacterWidth ( ) ;
BlockContainer . defFontSizes [ 1 ] = big . getCharacterHeight ( ) ;
BlockContainer . defFontSizes [ 2 ] = small . getCharacterWidth ( ) ;
BlockContainer . defFontSizes [ 3 ] = small . getCharacterHeight ( ) ;
BlockContainer . initialized = true ;
2017-03-03 23:06:43 +01:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public static BinaryFont getDefaultFont ( final boolean small ) {
BlockContainer . checkInitialized ( ) ;
return BlockContainer . defFonts [ small ? 1 : 0 ] ;
2017-03-03 23:06:43 +01:00
}
public static int getDefaultColor ( ) {
2018-09-22 11:17:30 +02:00
return BlockContainer . defColor ;
2017-03-03 23:06:43 +01:00
}
2018-09-22 11:17:30 +02:00
public static int getDefaultCharWidth ( final boolean b ) {
BlockContainer . checkInitialized ( ) ;
return BlockContainer . defFontSizes [ b ? 2 : 0 ] ;
2017-03-03 23:06:43 +01:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public static int getDefaultCharHeight ( final boolean b ) {
BlockContainer . checkInitialized ( ) ;
return BlockContainer . defFontSizes [ b ? 3 : 1 ] ;
2017-03-03 23:06:43 +01:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public static void drawCaret ( final GraphicEngine ge , final Renderer r , final Caret caret , final boolean small ,
final int x , final int y , final int height ) {
2017-03-26 22:44:09 +02:00
if ( caret . getState ( ) = = CaretState . VISIBLE_ON ) {
2018-09-22 11:17:30 +02:00
r . glColor ( BlockContainer . getDefaultColor ( ) ) ;
2017-09-24 18:47:30 +02:00
r . glFillColor ( x , y , small ? 2 : 3 , height ) ;
2017-05-05 22:27:11 +02:00
caret . setLastLocation ( x , y ) ;
2017-09-24 18:47:30 +02:00
caret . setLastSize ( small ? 2 : 3 , height ) ;
2017-03-26 22:44:09 +02:00
}
2017-03-03 23:06:43 +01:00
}
2018-09-22 11:17:30 +02:00
public void setSmall ( final boolean small ) {
2017-03-03 23:06:43 +01:00
this . small = small ;
2018-05-12 21:18:29 +02:00
if ( autoMinimums ) {
minWidth = BlockContainer . getDefaultCharWidth ( small ) ;
minHeight = BlockContainer . getDefaultCharHeight ( small ) ;
2017-04-11 22:04:44 +02:00
}
2018-09-22 11:17:30 +02:00
for ( final Block b : content )
2017-04-11 22:04:44 +02:00
b . setSmall ( small ) ;
2017-03-03 23:06:43 +01:00
recomputeDimensions ( ) ;
}
public ObjectArrayList < Block > getContent ( ) {
return content . clone ( ) ;
}
2017-04-10 22:50:43 +02:00
2017-03-26 22:44:09 +02:00
private static void checkInitialized ( ) {
2018-09-22 11:17:30 +02:00
if ( ! BlockContainer . initialized )
2018-09-04 12:12:41 +02:00
Engine . getPlatform ( ) . throwNewExceptionInInitializerError ( " Please initialize BlockContainer by running the method BlockContainer.initialize(...) first! " ) ;
2017-03-26 22:44:09 +02:00
}
2017-04-09 22:01:03 +02:00
public int computeCaretMaxBound ( ) {
int maxpos = 0 ;
2018-09-22 11:17:30 +02:00
for ( final Block b : content )
2017-04-10 22:50:43 +02:00
maxpos + = 1 + b . computeCaretMaxBound ( ) ;
return maxpos + 1 ;
2017-04-09 22:01:03 +02:00
}
2017-04-10 22:50:43 +02:00
2018-09-22 11:17:30 +02:00
public Function toFunction ( final MathContext context ) throws Error {
2018-05-12 21:18:29 +02:00
final ObjectArrayList < Block > blocks = getContent ( ) ;
2017-05-26 22:37:18 +02:00
final ObjectArrayList < Feature > blockFeatures = new ObjectArrayList < > ( ) ;
for ( final Block block : blocks ) {
final Feature blockFeature = block . toFeature ( context ) ;
2018-09-22 11:17:30 +02:00
if ( blockFeature = = null )
2017-09-24 18:47:30 +02:00
throw new Error ( Errors . NOT_IMPLEMENTED , " The block " + block . getClass ( ) . getSimpleName ( ) + " isn't a known Block " ) ;
2017-05-26 22:37:18 +02:00
blockFeatures . add ( blockFeature ) ;
}
final Function result = MathParser . joinFeatures ( context , blockFeatures ) ;
return result ;
}
2017-09-24 18:47:30 +02:00
2017-03-03 23:06:43 +01:00
}