001 package net.minecraft.client.gui.inventory;
002
003 import cpw.mods.fml.relauncher.Side;
004 import cpw.mods.fml.relauncher.SideOnly;
005 import java.util.List;
006 import net.minecraft.client.Minecraft;
007 import net.minecraft.client.gui.GuiScreen;
008 import net.minecraft.client.renderer.OpenGlHelper;
009 import net.minecraft.client.renderer.RenderHelper;
010 import net.minecraft.client.renderer.entity.RenderItem;
011 import net.minecraft.entity.player.InventoryPlayer;
012 import net.minecraft.inventory.Container;
013 import net.minecraft.inventory.Slot;
014 import net.minecraft.item.ItemStack;
015 import net.minecraft.util.MathHelper;
016 import org.lwjgl.input.Keyboard;
017 import org.lwjgl.opengl.GL11;
018 import org.lwjgl.opengl.GL12;
019
020 @SideOnly(Side.CLIENT)
021 public abstract class GuiContainer extends GuiScreen
022 {
023 /** Stacks renderer. Icons, stack size, health, etc... */
024 protected static RenderItem itemRenderer = new RenderItem();
025
026 /** The X size of the inventory window in pixels. */
027 protected int xSize = 176;
028
029 /** The Y size of the inventory window in pixels. */
030 protected int ySize = 166;
031
032 /** A list of the players inventory slots. */
033 public Container inventorySlots;
034
035 /**
036 * Starting X position for the Gui. Inconsistent use for Gui backgrounds.
037 */
038 protected int guiLeft;
039
040 /**
041 * Starting Y position for the Gui. Inconsistent use for Gui backgrounds.
042 */
043 protected int guiTop;
044 private Slot theSlot;
045
046 /** Used when touchscreen is enabled */
047 private Slot clickedSlot = null;
048 private boolean field_90018_r = false;
049
050 /** Used when touchscreen is enabled */
051 private ItemStack draggedStack = null;
052 private int field_85049_r = 0;
053 private int field_85048_s = 0;
054 private Slot returningStackDestSlot = null;
055 private long returningStackTime = 0L;
056
057 /** Used when touchscreen is enabled */
058 private ItemStack returningStack = null;
059 private Slot field_92033_y = null;
060 private long field_92032_z = 0L;
061
062 public GuiContainer(Container par1Container)
063 {
064 this.inventorySlots = par1Container;
065 }
066
067 /**
068 * Adds the buttons (and other controls) to the screen in question.
069 */
070 public void initGui()
071 {
072 super.initGui();
073 this.mc.thePlayer.openContainer = this.inventorySlots;
074 this.guiLeft = (this.width - this.xSize) / 2;
075 this.guiTop = (this.height - this.ySize) / 2;
076 }
077
078 /**
079 * Draws the screen and all the components in it.
080 */
081 public void drawScreen(int par1, int par2, float par3)
082 {
083 this.drawDefaultBackground();
084 int var4 = this.guiLeft;
085 int var5 = this.guiTop;
086 this.drawGuiContainerBackgroundLayer(par3, par1, par2);
087 GL11.glDisable(GL12.GL_RESCALE_NORMAL);
088 RenderHelper.disableStandardItemLighting();
089 GL11.glDisable(GL11.GL_LIGHTING);
090 GL11.glDisable(GL11.GL_DEPTH_TEST);
091 super.drawScreen(par1, par2, par3);
092 RenderHelper.enableGUIStandardItemLighting();
093 GL11.glPushMatrix();
094 GL11.glTranslatef((float)var4, (float)var5, 0.0F);
095 GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
096 GL11.glEnable(GL12.GL_RESCALE_NORMAL);
097 this.theSlot = null;
098 short var6 = 240;
099 short var7 = 240;
100 OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)var6 / 1.0F, (float)var7 / 1.0F);
101 GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
102 int var9;
103
104 for (int var13 = 0; var13 < this.inventorySlots.inventorySlots.size(); ++var13)
105 {
106 Slot var14 = (Slot)this.inventorySlots.inventorySlots.get(var13);
107 this.drawSlotInventory(var14);
108
109 if (this.isMouseOverSlot(var14, par1, par2))
110 {
111 this.theSlot = var14;
112 GL11.glDisable(GL11.GL_LIGHTING);
113 GL11.glDisable(GL11.GL_DEPTH_TEST);
114 int var8 = var14.xDisplayPosition;
115 var9 = var14.yDisplayPosition;
116 this.drawGradientRect(var8, var9, var8 + 16, var9 + 16, -2130706433, -2130706433);
117 GL11.glEnable(GL11.GL_LIGHTING);
118 GL11.glEnable(GL11.GL_DEPTH_TEST);
119 }
120 }
121
122 this.drawGuiContainerForegroundLayer(par1, par2);
123 InventoryPlayer var15 = this.mc.thePlayer.inventory;
124 ItemStack var16 = this.draggedStack == null ? var15.getItemStack() : this.draggedStack;
125
126 if (var16 != null)
127 {
128 byte var18 = 8;
129 var9 = this.draggedStack == null ? 8 : 16;
130
131 if (this.draggedStack != null && this.field_90018_r)
132 {
133 var16 = var16.copy();
134 var16.stackSize = MathHelper.ceiling_float_int((float)var16.stackSize / 2.0F);
135 }
136
137 this.drawItemStack(var16, par1 - var4 - var18, par2 - var5 - var9);
138 }
139
140 if (this.returningStack != null)
141 {
142 float var17 = (float)(Minecraft.getSystemTime() - this.returningStackTime) / 100.0F;
143
144 if (var17 >= 1.0F)
145 {
146 var17 = 1.0F;
147 this.returningStack = null;
148 }
149
150 var9 = this.returningStackDestSlot.xDisplayPosition - this.field_85049_r;
151 int var10 = this.returningStackDestSlot.yDisplayPosition - this.field_85048_s;
152 int var11 = this.field_85049_r + (int)((float)var9 * var17);
153 int var12 = this.field_85048_s + (int)((float)var10 * var17);
154 this.drawItemStack(this.returningStack, var11, var12);
155 }
156
157 if (var15.getItemStack() == null && this.theSlot != null && this.theSlot.getHasStack())
158 {
159 ItemStack var19 = this.theSlot.getStack();
160 this.drawItemStackTooltip(var19, par1 - var4 + 8, par2 - var5 + 8);
161 }
162
163 GL11.glPopMatrix();
164 GL11.glEnable(GL11.GL_LIGHTING);
165 GL11.glEnable(GL11.GL_DEPTH_TEST);
166 RenderHelper.enableStandardItemLighting();
167 }
168
169 private void drawItemStack(ItemStack par1ItemStack, int par2, int par3)
170 {
171 GL11.glTranslatef(0.0F, 0.0F, 32.0F);
172 this.zLevel = 200.0F;
173 itemRenderer.zLevel = 200.0F;
174 itemRenderer.renderItemAndEffectIntoGUI(this.fontRenderer, this.mc.renderEngine, par1ItemStack, par2, par3);
175 itemRenderer.renderItemOverlayIntoGUI(this.fontRenderer, this.mc.renderEngine, par1ItemStack, par2, par3 - (this.draggedStack == null ? 0 : 8));
176 this.zLevel = 0.0F;
177 itemRenderer.zLevel = 0.0F;
178 }
179
180 protected void drawItemStackTooltip(ItemStack par1ItemStack, int par2, int par3)
181 {
182 GL11.glDisable(GL12.GL_RESCALE_NORMAL);
183 RenderHelper.disableStandardItemLighting();
184 GL11.glDisable(GL11.GL_LIGHTING);
185 GL11.glDisable(GL11.GL_DEPTH_TEST);
186 List var4 = par1ItemStack.getTooltip(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips);
187
188 if (!var4.isEmpty())
189 {
190 int var5 = 0;
191 int var6;
192 int var7;
193
194 for (var6 = 0; var6 < var4.size(); ++var6)
195 {
196 var7 = this.fontRenderer.getStringWidth((String)var4.get(var6));
197
198 if (var7 > var5)
199 {
200 var5 = var7;
201 }
202 }
203
204 var6 = par2 + 12;
205 var7 = par3 - 12;
206 int var9 = 8;
207
208 if (var4.size() > 1)
209 {
210 var9 += 2 + (var4.size() - 1) * 10;
211 }
212
213 if (this.guiTop + var7 + var9 + 6 > this.height)
214 {
215 var7 = this.height - var9 - this.guiTop - 6;
216 }
217
218 this.zLevel = 300.0F;
219 itemRenderer.zLevel = 300.0F;
220 int var10 = -267386864;
221 this.drawGradientRect(var6 - 3, var7 - 4, var6 + var5 + 3, var7 - 3, var10, var10);
222 this.drawGradientRect(var6 - 3, var7 + var9 + 3, var6 + var5 + 3, var7 + var9 + 4, var10, var10);
223 this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, var7 + var9 + 3, var10, var10);
224 this.drawGradientRect(var6 - 4, var7 - 3, var6 - 3, var7 + var9 + 3, var10, var10);
225 this.drawGradientRect(var6 + var5 + 3, var7 - 3, var6 + var5 + 4, var7 + var9 + 3, var10, var10);
226 int var11 = 1347420415;
227 int var12 = (var11 & 16711422) >> 1 | var11 & -16777216;
228 this.drawGradientRect(var6 - 3, var7 - 3 + 1, var6 - 3 + 1, var7 + var9 + 3 - 1, var11, var12);
229 this.drawGradientRect(var6 + var5 + 2, var7 - 3 + 1, var6 + var5 + 3, var7 + var9 + 3 - 1, var11, var12);
230 this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, var7 - 3 + 1, var11, var11);
231 this.drawGradientRect(var6 - 3, var7 + var9 + 2, var6 + var5 + 3, var7 + var9 + 3, var12, var12);
232
233 for (int var13 = 0; var13 < var4.size(); ++var13)
234 {
235 String var14 = (String)var4.get(var13);
236
237 if (var13 == 0)
238 {
239 var14 = "\u00a7" + Integer.toHexString(par1ItemStack.getRarity().rarityColor) + var14;
240 }
241 else
242 {
243 var14 = "\u00a77" + var14;
244 }
245
246 this.fontRenderer.drawStringWithShadow(var14, var6, var7, -1);
247
248 if (var13 == 0)
249 {
250 var7 += 2;
251 }
252
253 var7 += 10;
254 }
255
256 this.zLevel = 0.0F;
257 itemRenderer.zLevel = 0.0F;
258 }
259 }
260
261 /**
262 * Draws the text when mouse is over creative inventory tab. Params: current creative tab to be checked, current
263 * mouse x position, current mouse y position.
264 */
265 protected void drawCreativeTabHoveringText(String par1Str, int par2, int par3)
266 {
267 GL11.glDisable(GL12.GL_RESCALE_NORMAL);
268 RenderHelper.disableStandardItemLighting();
269 GL11.glDisable(GL11.GL_LIGHTING);
270 GL11.glDisable(GL11.GL_DEPTH_TEST);
271 int var4 = this.fontRenderer.getStringWidth(par1Str);
272 int var5 = par2 + 12;
273 int var6 = par3 - 12;
274 byte var8 = 8;
275 this.zLevel = 300.0F;
276 itemRenderer.zLevel = 300.0F;
277 int var9 = -267386864;
278 this.drawGradientRect(var5 - 3, var6 - 4, var5 + var4 + 3, var6 - 3, var9, var9);
279 this.drawGradientRect(var5 - 3, var6 + var8 + 3, var5 + var4 + 3, var6 + var8 + 4, var9, var9);
280 this.drawGradientRect(var5 - 3, var6 - 3, var5 + var4 + 3, var6 + var8 + 3, var9, var9);
281 this.drawGradientRect(var5 - 4, var6 - 3, var5 - 3, var6 + var8 + 3, var9, var9);
282 this.drawGradientRect(var5 + var4 + 3, var6 - 3, var5 + var4 + 4, var6 + var8 + 3, var9, var9);
283 int var10 = 1347420415;
284 int var11 = (var10 & 16711422) >> 1 | var10 & -16777216;
285 this.drawGradientRect(var5 - 3, var6 - 3 + 1, var5 - 3 + 1, var6 + var8 + 3 - 1, var10, var11);
286 this.drawGradientRect(var5 + var4 + 2, var6 - 3 + 1, var5 + var4 + 3, var6 + var8 + 3 - 1, var10, var11);
287 this.drawGradientRect(var5 - 3, var6 - 3, var5 + var4 + 3, var6 - 3 + 1, var10, var10);
288 this.drawGradientRect(var5 - 3, var6 + var8 + 2, var5 + var4 + 3, var6 + var8 + 3, var11, var11);
289 this.fontRenderer.drawStringWithShadow(par1Str, var5, var6, -1);
290 this.zLevel = 0.0F;
291 itemRenderer.zLevel = 0.0F;
292 GL11.glEnable(GL11.GL_LIGHTING);
293 GL11.glEnable(GL11.GL_DEPTH_TEST);
294 RenderHelper.enableStandardItemLighting();
295 GL11.glEnable(GL12.GL_RESCALE_NORMAL);
296 }
297
298 /**
299 * Draw the foreground layer for the GuiContainer (everything in front of the items)
300 */
301 protected void drawGuiContainerForegroundLayer(int par1, int par2) {}
302
303 /**
304 * Draw the background layer for the GuiContainer (everything behind the items)
305 */
306 protected abstract void drawGuiContainerBackgroundLayer(float var1, int var2, int var3);
307
308 /**
309 * Draws an inventory slot
310 */
311 protected void drawSlotInventory(Slot par1Slot)
312 {
313 int var2 = par1Slot.xDisplayPosition;
314 int var3 = par1Slot.yDisplayPosition;
315 ItemStack var4 = par1Slot.getStack();
316 boolean var5 = par1Slot == this.clickedSlot && this.draggedStack != null && !this.field_90018_r;
317
318 if (par1Slot == this.clickedSlot && this.draggedStack != null && this.field_90018_r && var4 != null)
319 {
320 var4 = var4.copy();
321 var4.stackSize /= 2;
322 }
323
324 this.zLevel = 100.0F;
325 itemRenderer.zLevel = 100.0F;
326
327 if (var4 == null)
328 {
329 int var6 = par1Slot.getBackgroundIconIndex();
330
331 if (var6 >= 0)
332 {
333 GL11.glDisable(GL11.GL_LIGHTING);
334 this.mc.renderEngine.bindTexture(this.mc.renderEngine.getTexture(par1Slot.getBackgroundIconTexture()));
335 this.drawTexturedModalRect(var2, var3, var6 % 16 * 16, var6 / 16 * 16, 16, 16);
336 GL11.glEnable(GL11.GL_LIGHTING);
337 var5 = true;
338 }
339 }
340
341 if (!var5)
342 {
343 GL11.glEnable(GL11.GL_DEPTH_TEST);
344 itemRenderer.renderItemAndEffectIntoGUI(this.fontRenderer, this.mc.renderEngine, var4, var2, var3);
345 itemRenderer.renderItemOverlayIntoGUI(this.fontRenderer, this.mc.renderEngine, var4, var2, var3);
346 }
347
348 itemRenderer.zLevel = 0.0F;
349 this.zLevel = 0.0F;
350 }
351
352 /**
353 * Returns the slot at the given coordinates or null if there is none.
354 */
355 private Slot getSlotAtPosition(int par1, int par2)
356 {
357 for (int var3 = 0; var3 < this.inventorySlots.inventorySlots.size(); ++var3)
358 {
359 Slot var4 = (Slot)this.inventorySlots.inventorySlots.get(var3);
360
361 if (this.isMouseOverSlot(var4, par1, par2))
362 {
363 return var4;
364 }
365 }
366
367 return null;
368 }
369
370 /**
371 * Called when the mouse is clicked.
372 */
373 protected void mouseClicked(int par1, int par2, int par3)
374 {
375 super.mouseClicked(par1, par2, par3);
376 boolean var4 = par3 == this.mc.gameSettings.keyBindPickBlock.keyCode + 100;
377
378 if (par3 == 0 || par3 == 1 || var4)
379 {
380 Slot var5 = this.getSlotAtPosition(par1, par2);
381 int var6 = this.guiLeft;
382 int var7 = this.guiTop;
383 boolean var8 = par1 < var6 || par2 < var7 || par1 >= var6 + this.xSize || par2 >= var7 + this.ySize;
384 int var9 = -1;
385
386 if (var5 != null)
387 {
388 var9 = var5.slotNumber;
389 }
390
391 if (var8)
392 {
393 var9 = -999;
394 }
395
396 if (this.mc.gameSettings.touchscreen && var8 && this.mc.thePlayer.inventory.getItemStack() == null)
397 {
398 this.mc.displayGuiScreen((GuiScreen)null);
399 return;
400 }
401
402 if (var9 != -1)
403 {
404 if (this.mc.gameSettings.touchscreen)
405 {
406 if (var5 != null && var5.getHasStack())
407 {
408 this.clickedSlot = var5;
409 this.draggedStack = null;
410 this.field_90018_r = par3 == 1;
411 }
412 else
413 {
414 this.clickedSlot = null;
415 }
416 }
417 else if (var4)
418 {
419 this.handleMouseClick(var5, var9, par3, 3);
420 }
421 else
422 {
423 boolean var10 = var9 != -999 && (Keyboard.isKeyDown(42) || Keyboard.isKeyDown(54));
424 this.handleMouseClick(var5, var9, par3, var10 ? 1 : 0);
425 }
426 }
427 }
428 }
429
430 protected void func_85041_a(int par1, int par2, int par3, long par4)
431 {
432 if (this.clickedSlot != null && this.mc.gameSettings.touchscreen)
433 {
434 if (par3 == 0 || par3 == 1)
435 {
436 Slot var6 = this.getSlotAtPosition(par1, par2);
437
438 if (this.draggedStack == null)
439 {
440 if (var6 != this.clickedSlot)
441 {
442 this.draggedStack = this.clickedSlot.getStack().copy();
443 }
444 }
445 else if (this.draggedStack.stackSize > 1 && var6 != null && this.func_92031_b(var6))
446 {
447 long var7 = Minecraft.getSystemTime();
448
449 if (this.field_92033_y == var6)
450 {
451 if (var7 - this.field_92032_z > 500L)
452 {
453 this.handleMouseClick(this.clickedSlot, this.clickedSlot.slotNumber, 0, 0);
454 this.handleMouseClick(var6, var6.slotNumber, 1, 0);
455 this.handleMouseClick(this.clickedSlot, this.clickedSlot.slotNumber, 0, 0);
456 this.field_92032_z = var7 + 750L;
457 --this.draggedStack.stackSize;
458 }
459 }
460 else
461 {
462 this.field_92033_y = var6;
463 this.field_92032_z = var7;
464 }
465 }
466 }
467 }
468 }
469
470 /**
471 * Called when the mouse is moved or a mouse button is released. Signature: (mouseX, mouseY, which) which==-1 is
472 * mouseMove, which==0 or which==1 is mouseUp
473 */
474 protected void mouseMovedOrUp(int par1, int par2, int par3)
475 {
476 if (this.clickedSlot != null && this.mc.gameSettings.touchscreen)
477 {
478 if (par3 == 0 || par3 == 1)
479 {
480 Slot var4 = this.getSlotAtPosition(par1, par2);
481 int var5 = this.guiLeft;
482 int var6 = this.guiTop;
483 boolean var7 = par1 < var5 || par2 < var6 || par1 >= var5 + this.xSize || par2 >= var6 + this.ySize;
484 int var8 = -1;
485
486 if (var4 != null)
487 {
488 var8 = var4.slotNumber;
489 }
490
491 if (var7)
492 {
493 var8 = -999;
494 }
495
496 if (this.draggedStack == null && var4 != this.clickedSlot)
497 {
498 this.draggedStack = this.clickedSlot.getStack();
499 }
500
501 boolean var9 = this.func_92031_b(var4);
502
503 if (var8 != -1 && this.draggedStack != null && var9)
504 {
505 this.handleMouseClick(this.clickedSlot, this.clickedSlot.slotNumber, par3, 0);
506 this.handleMouseClick(var4, var8, 0, 0);
507
508 if (this.mc.thePlayer.inventory.getItemStack() != null)
509 {
510 this.handleMouseClick(this.clickedSlot, this.clickedSlot.slotNumber, par3, 0);
511 this.field_85049_r = par1 - var5;
512 this.field_85048_s = par2 - var6;
513 this.returningStackDestSlot = this.clickedSlot;
514 this.returningStack = this.draggedStack;
515 this.returningStackTime = Minecraft.getSystemTime();
516 }
517 else
518 {
519 this.returningStack = null;
520 }
521 }
522 else if (this.draggedStack != null)
523 {
524 this.field_85049_r = par1 - var5;
525 this.field_85048_s = par2 - var6;
526 this.returningStackDestSlot = this.clickedSlot;
527 this.returningStack = this.draggedStack;
528 this.returningStackTime = Minecraft.getSystemTime();
529 }
530
531 this.draggedStack = null;
532 this.clickedSlot = null;
533 }
534 }
535 }
536
537 private boolean func_92031_b(Slot par1Slot)
538 {
539 boolean var2 = par1Slot == null || !par1Slot.getHasStack();
540
541 if (par1Slot != null && par1Slot.getHasStack() && this.draggedStack != null && ItemStack.areItemStackTagsEqual(par1Slot.getStack(), this.draggedStack))
542 {
543 var2 |= par1Slot.getStack().stackSize + this.draggedStack.stackSize <= this.draggedStack.getMaxStackSize();
544 }
545
546 return var2;
547 }
548
549 /**
550 * Returns if the passed mouse position is over the specified slot.
551 */
552 private boolean isMouseOverSlot(Slot par1Slot, int par2, int par3)
553 {
554 return this.func_74188_c(par1Slot.xDisplayPosition, par1Slot.yDisplayPosition, 16, 16, par2, par3);
555 }
556
557 protected boolean func_74188_c(int par1, int par2, int par3, int par4, int par5, int par6)
558 {
559 int var7 = this.guiLeft;
560 int var8 = this.guiTop;
561 par5 -= var7;
562 par6 -= var8;
563 return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && par6 < par2 + par4 + 1;
564 }
565
566 protected void handleMouseClick(Slot par1Slot, int par2, int par3, int par4)
567 {
568 if (par1Slot != null)
569 {
570 par2 = par1Slot.slotNumber;
571 }
572
573 this.mc.playerController.windowClick(this.inventorySlots.windowId, par2, par3, par4, this.mc.thePlayer);
574 }
575
576 /**
577 * Fired when a key is typed. This is the equivalent of KeyListener.keyTyped(KeyEvent e).
578 */
579 protected void keyTyped(char par1, int par2)
580 {
581 if (par2 == 1 || par2 == this.mc.gameSettings.keyBindInventory.keyCode)
582 {
583 this.mc.thePlayer.closeScreen();
584 }
585
586 this.func_82319_a(par2);
587
588 if (par2 == this.mc.gameSettings.keyBindPickBlock.keyCode && this.theSlot != null && this.theSlot.getHasStack())
589 {
590 this.handleMouseClick(this.theSlot, this.theSlot.slotNumber, this.ySize, 3);
591 }
592 }
593
594 protected boolean func_82319_a(int par1)
595 {
596 if (this.mc.thePlayer.inventory.getItemStack() == null && this.theSlot != null)
597 {
598 for (int var2 = 0; var2 < 9; ++var2)
599 {
600 if (par1 == 2 + var2)
601 {
602 this.handleMouseClick(this.theSlot, this.theSlot.slotNumber, var2, 2);
603 return true;
604 }
605 }
606 }
607
608 return false;
609 }
610
611 /**
612 * Called when the screen is unloaded. Used to disable keyboard repeat events
613 */
614 public void onGuiClosed()
615 {
616 if (this.mc.thePlayer != null)
617 {
618 this.inventorySlots.onCraftGuiClosed(this.mc.thePlayer);
619 }
620 }
621
622 /**
623 * Returns true if this GUI should pause the game when it is displayed in single-player
624 */
625 public boolean doesGuiPauseGame()
626 {
627 return false;
628 }
629
630 /**
631 * Called from the main game loop to update the screen.
632 */
633 public void updateScreen()
634 {
635 super.updateScreen();
636
637 if (!this.mc.thePlayer.isEntityAlive() || this.mc.thePlayer.isDead)
638 {
639 this.mc.thePlayer.closeScreen();
640 }
641 }
642 }