240 lines
8.5 KiB
Java
240 lines
8.5 KiB
Java
/*
|
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
|
* Send enquiries to dratcliffe@gmail.com
|
|
*/
|
|
package dan200.computercraft.client.gui;
|
|
|
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
|
import dan200.computercraft.ComputerCraft;
|
|
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
|
import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
|
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
|
|
import dan200.computercraft.shared.computer.core.ClientComputer;
|
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
|
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
|
|
import dan200.computercraft.shared.computer.upload.FileUpload;
|
|
import dan200.computercraft.shared.computer.upload.UploadResult;
|
|
import dan200.computercraft.shared.network.NetworkHandler;
|
|
import dan200.computercraft.shared.network.server.ContinueUploadMessage;
|
|
import dan200.computercraft.shared.network.server.UploadFileMessage;
|
|
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
|
|
import net.minecraft.entity.player.PlayerInventory;
|
|
import net.minecraft.util.text.ITextComponent;
|
|
import net.minecraft.util.text.TranslationTextComponent;
|
|
import org.lwjgl.glfw.GLFW;
|
|
|
|
import javax.annotation.Nonnull;
|
|
import java.io.IOException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.channels.SeekableByteChannel;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
public abstract class ComputerScreenBase<T extends ContainerComputerBase> extends ContainerScreen<T>
|
|
{
|
|
private static final ITextComponent OK = new TranslationTextComponent( "gui.ok" );
|
|
private static final ITextComponent CANCEL = new TranslationTextComponent( "gui.cancel" );
|
|
private static final ITextComponent OVERWRITE = new TranslationTextComponent( "gui.computercraft.upload.overwrite_button" );
|
|
|
|
protected WidgetTerminal terminal;
|
|
protected final ClientComputer computer;
|
|
protected final ComputerFamily family;
|
|
|
|
protected final int sidebarYOffset;
|
|
|
|
public ComputerScreenBase( T container, PlayerInventory player, ITextComponent title, int sidebarYOffset )
|
|
{
|
|
super( container, player, title );
|
|
computer = (ClientComputer) container.getComputer();
|
|
family = container.getFamily();
|
|
this.sidebarYOffset = sidebarYOffset;
|
|
}
|
|
|
|
protected abstract WidgetTerminal createTerminal();
|
|
|
|
@Override
|
|
protected void init()
|
|
{
|
|
super.init();
|
|
minecraft.keyboardHandler.setSendRepeatsToGui( true );
|
|
|
|
terminal = addButton( createTerminal() );
|
|
ComputerSidebar.addButtons( this, computer, this::addButton, leftPos, topPos + sidebarYOffset );
|
|
setFocused( terminal );
|
|
}
|
|
|
|
@Override
|
|
public void removed()
|
|
{
|
|
super.removed();
|
|
minecraft.keyboardHandler.setSendRepeatsToGui( false );
|
|
}
|
|
|
|
@Override
|
|
public void tick()
|
|
{
|
|
super.tick();
|
|
terminal.update();
|
|
}
|
|
|
|
@Override
|
|
public boolean keyPressed( int key, int scancode, int modifiers )
|
|
{
|
|
// Forward the tab key to the terminal, rather than moving between controls.
|
|
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal )
|
|
{
|
|
return getFocused().keyPressed( key, scancode, modifiers );
|
|
}
|
|
|
|
return super.keyPressed( key, scancode, modifiers );
|
|
}
|
|
|
|
|
|
@Override
|
|
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
|
|
{
|
|
renderBackground( stack );
|
|
super.render( stack, mouseX, mouseY, partialTicks );
|
|
renderTooltip( stack, mouseX, mouseY );
|
|
}
|
|
|
|
@Override
|
|
public boolean mouseClicked( double x, double y, int button )
|
|
{
|
|
boolean changed = super.mouseClicked( x, y, button );
|
|
// Clicking the terminate/shutdown button steals focus, which means then pressing "enter" will click the button
|
|
// again. Restore the focus to the terminal in these cases.
|
|
if( getFocused() instanceof DynamicImageButton ) setFocused( terminal );
|
|
return changed;
|
|
}
|
|
|
|
@Override
|
|
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
|
|
{
|
|
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
|
|
|| super.mouseDragged( x, y, button, deltaX, deltaY );
|
|
}
|
|
|
|
|
|
@Override
|
|
protected void renderLabels( @Nonnull MatrixStack transform, int mouseX, int mouseY )
|
|
{
|
|
// Skip rendering labels.
|
|
}
|
|
|
|
@Override
|
|
public void onFilesDrop( @Nonnull List<Path> files )
|
|
{
|
|
if( files.isEmpty() ) return;
|
|
|
|
if( computer == null || !computer.isOn() )
|
|
{
|
|
alert( UploadResult.FAILED_TITLE, UploadResult.COMPUTER_OFF_MSG );
|
|
return;
|
|
}
|
|
|
|
long size = 0;
|
|
|
|
List<FileUpload> toUpload = new ArrayList<>();
|
|
for( Path file : files )
|
|
{
|
|
// TODO: Recurse directories? If so, we probably want to shunt this off-thread.
|
|
if( !Files.isRegularFile( file ) ) continue;
|
|
|
|
try( SeekableByteChannel sbc = Files.newByteChannel( file ) )
|
|
{
|
|
long fileSize = sbc.size();
|
|
if( fileSize > UploadFileMessage.MAX_SIZE || (size += fileSize) >= UploadFileMessage.MAX_SIZE )
|
|
{
|
|
alert( UploadResult.FAILED_TITLE, UploadResult.TOO_MUCH_MSG );
|
|
return;
|
|
}
|
|
|
|
String name = file.getFileName().toString();
|
|
if( name.length() > UploadFileMessage.MAX_FILE_NAME )
|
|
{
|
|
alert( UploadResult.FAILED_TITLE, new TranslationTextComponent( "gui.computercraft.upload.failed.name_too_long" ) );
|
|
return;
|
|
}
|
|
|
|
ByteBuffer buffer = ByteBuffer.allocateDirect( (int) fileSize );
|
|
sbc.read( buffer );
|
|
buffer.flip();
|
|
|
|
byte[] digest = FileUpload.getDigest( buffer );
|
|
if( digest == null )
|
|
{
|
|
alert( UploadResult.FAILED_TITLE, new TranslationTextComponent( "gui.computercraft.upload.failed.corrupted" ) );
|
|
return;
|
|
}
|
|
|
|
toUpload.add( new FileUpload( name, buffer, digest ) );
|
|
}
|
|
catch( IOException e )
|
|
{
|
|
ComputerCraft.log.error( "Failed uploading files", e );
|
|
alert( UploadResult.FAILED_TITLE, new TranslationTextComponent( "gui.computercraft.upload.failed.generic", "Cannot compute checksum" ) );
|
|
}
|
|
}
|
|
|
|
if( toUpload.size() > UploadFileMessage.MAX_FILES )
|
|
{
|
|
alert( UploadResult.FAILED_TITLE, new TranslationTextComponent( "gui.computercraft.upload.failed.too_many_files" ) );
|
|
return;
|
|
}
|
|
|
|
if( toUpload.size() > 0 )
|
|
{
|
|
UploadFileMessage.send( computer.getInstanceID(), toUpload );
|
|
}
|
|
}
|
|
|
|
public void uploadResult( UploadResult result, ITextComponent message )
|
|
{
|
|
switch( result )
|
|
{
|
|
case SUCCESS:
|
|
alert( UploadResult.SUCCESS_TITLE, message );
|
|
break;
|
|
case ERROR:
|
|
alert( UploadResult.FAILED_TITLE, message );
|
|
break;
|
|
case CONFIRM_OVERWRITE:
|
|
OptionScreen.show(
|
|
minecraft, UploadResult.UPLOAD_OVERWRITE, message,
|
|
Arrays.asList(
|
|
OptionScreen.newButton( CANCEL, b -> cancelUpload() ),
|
|
OptionScreen.newButton( OVERWRITE, b -> continueUpload() )
|
|
),
|
|
this::cancelUpload
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void continueUpload()
|
|
{
|
|
if( minecraft.screen instanceof OptionScreen ) ((OptionScreen) minecraft.screen).disable();
|
|
NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) );
|
|
}
|
|
|
|
private void cancelUpload()
|
|
{
|
|
minecraft.setScreen( this );
|
|
NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), false ) );
|
|
}
|
|
|
|
private void alert( ITextComponent title, ITextComponent message )
|
|
{
|
|
OptionScreen.show( minecraft, title, message,
|
|
Collections.singletonList( OptionScreen.newButton( OK, b -> minecraft.setScreen( this ) ) ),
|
|
() -> minecraft.setScreen( this )
|
|
);
|
|
}
|
|
}
|