    001package net.minecraft.client.gui;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.io.ByteArrayOutputStream;
    006import java.io.DataOutputStream;
    007import net.minecraft.entity.player.EntityPlayer;
    008import net.minecraft.item.Item;
    009import net.minecraft.item.ItemStack;
    010import net.minecraft.nbt.NBTTagCompound;
    011import net.minecraft.nbt.NBTTagList;
    012import net.minecraft.nbt.NBTTagString;
    013import net.minecraft.network.packet.Packet;
    014import net.minecraft.network.packet.Packet250CustomPayload;
    015import net.minecraft.util.ChatAllowedCharacters;
    016import net.minecraft.util.EnumChatFormatting;
    017import net.minecraft.util.StatCollector;
    018import org.lwjgl.input.Keyboard;
    019import org.lwjgl.opengl.GL11;
    020
    021@SideOnly(Side.CLIENT)
    022public class GuiScreenBook extends GuiScreen
    023{
    024    /** The player editing the book */
    025    private final EntityPlayer editingPlayer;
    026    private final ItemStack itemstackBook;
    027
    028    /** Whether the book is signed or can still be edited */
    029    private final boolean bookIsUnsigned;
    030    private boolean bookModified;
    031    private boolean editingTitle;
    032
    033    /** Update ticks since the gui was opened */
    034    private int updateCount;
    035    private int bookImageWidth = 192;
    036    private int bookImageHeight = 192;
    037    private int bookTotalPages = 1;
    038    private int currPage;
    039    private NBTTagList bookPages;
    040    private String bookTitle = "";
    041    private GuiButtonNextPage buttonNextPage;
    042    private GuiButtonNextPage buttonPreviousPage;
    043    private GuiButton buttonDone;
    044
    045    /** The GuiButton to sign this book. */
    046    private GuiButton buttonSign;
    047    private GuiButton buttonFinalize;
    048    private GuiButton buttonCancel;
    049
    050    public GuiScreenBook(EntityPlayer par1EntityPlayer, ItemStack par2ItemStack, boolean par3)
    051    {
    052        this.editingPlayer = par1EntityPlayer;
    053        this.itemstackBook = par2ItemStack;
    054        this.bookIsUnsigned = par3;
    055
    056        if (par2ItemStack.hasTagCompound())
    057        {
    058            NBTTagCompound nbttagcompound = par2ItemStack.getTagCompound();
    059            this.bookPages = nbttagcompound.getTagList("pages");
    060
    061            if (this.bookPages != null)
    062            {
    063                this.bookPages = (NBTTagList)this.bookPages.copy();
    064                this.bookTotalPages = this.bookPages.tagCount();
    065
    066                if (this.bookTotalPages < 1)
    067                {
    068                    this.bookTotalPages = 1;
    069                }
    070            }
    071        }
    072
    073        if (this.bookPages == null && par3)
    074        {
    075            this.bookPages = new NBTTagList("pages");
    076            this.bookPages.appendTag(new NBTTagString("1", ""));
    077            this.bookTotalPages = 1;
    078        }
    079    }
    080
    081    /**
    082     * Called from the main game loop to update the screen.
    083     */
    084    public void updateScreen()
    085    {
    086        super.updateScreen();
    087        ++this.updateCount;
    088    }
    089
    090    /**
    091     * Adds the buttons (and other controls) to the screen in question.
    092     */
    093    public void initGui()
    094    {
    095        this.buttonList.clear();
    096        Keyboard.enableRepeatEvents(true);
    097
    098        if (this.bookIsUnsigned)
    099        {
    100            this.buttonList.add(this.buttonSign = new GuiButton(3, this.width / 2 - 100, 4 + this.bookImageHeight, 98, 20, StatCollector.translateToLocal("book.signButton")));
    101            this.buttonList.add(this.buttonDone = new GuiButton(0, this.width / 2 + 2, 4 + this.bookImageHeight, 98, 20, StatCollector.translateToLocal("gui.done")));
    102            this.buttonList.add(this.buttonFinalize = new GuiButton(5, this.width / 2 - 100, 4 + this.bookImageHeight, 98, 20, StatCollector.translateToLocal("book.finalizeButton")));
    103            this.buttonList.add(this.buttonCancel = new GuiButton(4, this.width / 2 + 2, 4 + this.bookImageHeight, 98, 20, StatCollector.translateToLocal("gui.cancel")));
    104        }
    105        else
    106        {
    107            this.buttonList.add(this.buttonDone = new GuiButton(0, this.width / 2 - 100, 4 + this.bookImageHeight, 200, 20, StatCollector.translateToLocal("gui.done")));
    108        }
    109
    110        int i = (this.width - this.bookImageWidth) / 2;
    111        byte b0 = 2;
    112        this.buttonList.add(this.buttonNextPage = new GuiButtonNextPage(1, i + 120, b0 + 154, true));
    113        this.buttonList.add(this.buttonPreviousPage = new GuiButtonNextPage(2, i + 38, b0 + 154, false));
    114        this.updateButtons();
    115    }
    116
    117    /**
    118     * Called when the screen is unloaded. Used to disable keyboard repeat events
    119     */
    120    public void onGuiClosed()
    121    {
    122        Keyboard.enableRepeatEvents(false);
    123    }
    124
    125    private void updateButtons()
    126    {
    127        this.buttonNextPage.drawButton = !this.editingTitle && (this.currPage < this.bookTotalPages - 1 || this.bookIsUnsigned);
    128        this.buttonPreviousPage.drawButton = !this.editingTitle && this.currPage > 0;
    129        this.buttonDone.drawButton = !this.bookIsUnsigned || !this.editingTitle;
    130
    131        if (this.bookIsUnsigned)
    132        {
    133            this.buttonSign.drawButton = !this.editingTitle;
    134            this.buttonCancel.drawButton = this.editingTitle;
    135            this.buttonFinalize.drawButton = this.editingTitle;
    136            this.buttonFinalize.enabled = this.bookTitle.trim().length() > 0;
    137        }
    138    }
    139
    140    private void sendBookToServer(boolean par1)
    141    {
    142        if (this.bookIsUnsigned && this.bookModified)
    143        {
    144            if (this.bookPages != null)
    145            {
    146                while (this.bookPages.tagCount() > 1)
    147                {
    148                    NBTTagString nbttagstring = (NBTTagString)this.bookPages.tagAt(this.bookPages.tagCount() - 1);
    149
    150                    if (nbttagstring.data != null && nbttagstring.data.length() != 0)
    151                    {
    152                        break;
    153                    }
    154
    155                    this.bookPages.removeTag(this.bookPages.tagCount() - 1);
    156                }
    157
    158                if (this.itemstackBook.hasTagCompound())
    159                {
    160                    NBTTagCompound nbttagcompound = this.itemstackBook.getTagCompound();
    161                    nbttagcompound.setTag("pages", this.bookPages);
    162                }
    163                else
    164                {
    165                    this.itemstackBook.setTagInfo("pages", this.bookPages);
    166                }
    167
    168                String s = "MC|BEdit";
    169
    170                if (par1)
    171                {
    172                    s = "MC|BSign";
    173                    this.itemstackBook.setTagInfo("author", new NBTTagString("author", this.editingPlayer.username));
    174                    this.itemstackBook.setTagInfo("title", new NBTTagString("title", this.bookTitle.trim()));
    175                    this.itemstackBook.itemID = Item.writtenBook.itemID;
    176                }
    177
    178                ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
    179                DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);
    180
    181                try
    182                {
    183                    Packet.writeItemStack(this.itemstackBook, dataoutputstream);
    184                    this.mc.getNetHandler().addToSendQueue(new Packet250CustomPayload(s, bytearrayoutputstream.toByteArray()));
    185                }
    186                catch (Exception exception)
    187                {
    188                    exception.printStackTrace();
    189                }
    190            }
    191        }
    192    }
    193
    194    /**
    195     * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
    196     */
    197    protected void actionPerformed(GuiButton par1GuiButton)
    198    {
    199        if (par1GuiButton.enabled)
    200        {
    201            if (par1GuiButton.id == 0)
    202            {
    203                this.mc.displayGuiScreen((GuiScreen)null);
    204                this.sendBookToServer(false);
    205            }
    206            else if (par1GuiButton.id == 3 && this.bookIsUnsigned)
    207            {
    208                this.editingTitle = true;
    209            }
    210            else if (par1GuiButton.id == 1)
    211            {
    212                if (this.currPage < this.bookTotalPages - 1)
    213                {
    214                    ++this.currPage;
    215                }
    216                else if (this.bookIsUnsigned)
    217                {
    218                    this.addNewPage();
    219
    220                    if (this.currPage < this.bookTotalPages - 1)
    221                    {
    222                        ++this.currPage;
    223                    }
    224                }
    225            }
    226            else if (par1GuiButton.id == 2)
    227            {
    228                if (this.currPage > 0)
    229                {
    230                    --this.currPage;
    231                }
    232            }
    233            else if (par1GuiButton.id == 5 && this.editingTitle)
    234            {
    235                this.sendBookToServer(true);
    236                this.mc.displayGuiScreen((GuiScreen)null);
    237            }
    238            else if (par1GuiButton.id == 4 && this.editingTitle)
    239            {
    240                this.editingTitle = false;
    241            }
    242
    243            this.updateButtons();
    244        }
    245    }
    246
    247    private void addNewPage()
    248    {
    249        if (this.bookPages != null && this.bookPages.tagCount() < 50)
    250        {
    251            this.bookPages.appendTag(new NBTTagString("" + (this.bookTotalPages + 1), ""));
    252            ++this.bookTotalPages;
    253            this.bookModified = true;
    254        }
    255    }
    256
    257    /**
    258     * Fired when a key is typed. This is the equivalent of KeyListener.keyTyped(KeyEvent e).
    259     */
    260    protected void keyTyped(char par1, int par2)
    261    {
    262        super.keyTyped(par1, par2);
    263
    264        if (this.bookIsUnsigned)
    265        {
    266            if (this.editingTitle)
    267            {
    268                this.func_74162_c(par1, par2);
    269            }
    270            else
    271            {
    272                this.keyTypedInBook(par1, par2);
    273            }
    274        }
    275    }
    276
    277    /**
    278     * Processes keystrokes when editing the text of a book
    279     */
    280    private void keyTypedInBook(char par1, int par2)
    281    {
    282        switch (par1)
    283        {
    284            case 22:
    285                this.func_74160_b(GuiScreen.getClipboardString());
    286                return;
    287            default:
    288                switch (par2)
    289                {
    290                    case 14:
    291                        String s = this.func_74158_i();
    292
    293                        if (s.length() > 0)
    294                        {
    295                            this.func_74159_a(s.substring(0, s.length() - 1));
    296                        }
    297
    298                        return;
    299                    case 28:
    300                        this.func_74160_b("\n");
    301                        return;
    302                    default:
    303                        if (ChatAllowedCharacters.isAllowedCharacter(par1))
    304                        {
    305                            this.func_74160_b(Character.toString(par1));
    306                        }
    307                }
    308        }
    309    }
    310
    311    private void func_74162_c(char par1, int par2)
    312    {
    313        switch (par2)
    314        {
    315            case 14:
    316                if (this.bookTitle.length() > 0)
    317                {
    318                    this.bookTitle = this.bookTitle.substring(0, this.bookTitle.length() - 1);
    319                    this.updateButtons();
    320                }
    321
    322                return;
    323            case 28:
    324                if (this.bookTitle.length() > 0)
    325                {
    326                    this.sendBookToServer(true);
    327                    this.mc.displayGuiScreen((GuiScreen)null);
    328                }
    329
    330                return;
    331            default:
    332                if (this.bookTitle.length() < 16 && ChatAllowedCharacters.isAllowedCharacter(par1))
    333                {
    334                    this.bookTitle = this.bookTitle + Character.toString(par1);
    335                    this.updateButtons();
    336                    this.bookModified = true;
    337                }
    338        }
    339    }
    340
    341    private String func_74158_i()
    342    {
    343        if (this.bookPages != null && this.currPage >= 0 && this.currPage < this.bookPages.tagCount())
    344        {
    345            NBTTagString nbttagstring = (NBTTagString)this.bookPages.tagAt(this.currPage);
    346            return nbttagstring.toString();
    347        }
    348        else
    349        {
    350            return "";
    351        }
    352    }
    353
    354    private void func_74159_a(String par1Str)
    355    {
    356        if (this.bookPages != null && this.currPage >= 0 && this.currPage < this.bookPages.tagCount())
    357        {
    358            NBTTagString nbttagstring = (NBTTagString)this.bookPages.tagAt(this.currPage);
    359            nbttagstring.data = par1Str;
    360            this.bookModified = true;
    361        }
    362    }
    363
    364    private void func_74160_b(String par1Str)
    365    {
    366        String s1 = this.func_74158_i();
    367        String s2 = s1 + par1Str;
    368        int i = this.fontRenderer.splitStringWidth(s2 + "" + EnumChatFormatting.BLACK + "_", 118);
    369
    370        if (i <= 118 && s2.length() < 256)
    371        {
    372            this.func_74159_a(s2);
    373        }
    374    }
    375
    376    /**
    377     * Draws the screen and all the components in it.
    378     */
    379    public void drawScreen(int par1, int par2, float par3)
    380    {
    381        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
    382        this.mc.renderEngine.func_98187_b("/gui/book.png");
    383        int k = (this.width - this.bookImageWidth) / 2;
    384        byte b0 = 2;
    385        this.drawTexturedModalRect(k, b0, 0, 0, this.bookImageWidth, this.bookImageHeight);
    386        String s;
    387        String s1;
    388        int l;
    389
    390        if (this.editingTitle)
    391        {
    392            s = this.bookTitle;
    393
    394            if (this.bookIsUnsigned)
    395            {
    396                if (this.updateCount / 6 % 2 == 0)
    397                {
    398                    s = s + "" + EnumChatFormatting.BLACK + "_";
    399                }
    400                else
    401                {
    402                    s = s + "" + EnumChatFormatting.GRAY + "_";
    403                }
    404            }
    405
    406            s1 = StatCollector.translateToLocal("book.editTitle");
    407            l = this.fontRenderer.getStringWidth(s1);
    408            this.fontRenderer.drawString(s1, k + 36 + (116 - l) / 2, b0 + 16 + 16, 0);
    409            int i1 = this.fontRenderer.getStringWidth(s);
    410            this.fontRenderer.drawString(s, k + 36 + (116 - i1) / 2, b0 + 48, 0);
    411            String s2 = String.format(StatCollector.translateToLocal("book.byAuthor"), new Object[] {this.editingPlayer.username});
    412            int j1 = this.fontRenderer.getStringWidth(s2);
    413            this.fontRenderer.drawString(EnumChatFormatting.DARK_GRAY + s2, k + 36 + (116 - j1) / 2, b0 + 48 + 10, 0);
    414            String s3 = StatCollector.translateToLocal("book.finalizeWarning");
    415            this.fontRenderer.drawSplitString(s3, k + 36, b0 + 80, 116, 0);
    416        }
    417        else
    418        {
    419            s = String.format(StatCollector.translateToLocal("book.pageIndicator"), new Object[] {Integer.valueOf(this.currPage + 1), Integer.valueOf(this.bookTotalPages)});
    420            s1 = "";
    421
    422            if (this.bookPages != null && this.currPage >= 0 && this.currPage < this.bookPages.tagCount())
    423            {
    424                NBTTagString nbttagstring = (NBTTagString)this.bookPages.tagAt(this.currPage);
    425                s1 = nbttagstring.toString();
    426            }
    427
    428            if (this.bookIsUnsigned)
    429            {
    430                if (this.fontRenderer.getBidiFlag())
    431                {
    432                    s1 = s1 + "_";
    433                }
    434                else if (this.updateCount / 6 % 2 == 0)
    435                {
    436                    s1 = s1 + "" + EnumChatFormatting.BLACK + "_";
    437                }
    438                else
    439                {
    440                    s1 = s1 + "" + EnumChatFormatting.GRAY + "_";
    441                }
    442            }
    443
    444            l = this.fontRenderer.getStringWidth(s);
    445            this.fontRenderer.drawString(s, k - l + this.bookImageWidth - 44, b0 + 16, 0);
    446            this.fontRenderer.drawSplitString(s1, k + 36, b0 + 16 + 16, 116, 0);
    447        }
    448
    449        super.drawScreen(par1, par2, par3);
    450    }
    451}