public CraftTypeDisplay(
      int x,
      int y,
      int width,
      int height,
      GuiScrollBar scrollBar,
      Texture texture,
      RecipeCache recipeCache) {
    super(x, y, width, height, scrollBar, 32, 1);

    displayBackground = new BorderedTexture(texture, 117, 1, 1, 32, 2);

    this.recipeCache = recipeCache;
    recipeCache.addListener(this);
    initTypes(recipeCache);

    buttons[0] = new TexturedRect(0, 0, 28, 28, texture, 113, 76);
    buttons[1] = new TexturedRect(0, 0, 28, 28, texture, 113, 104);
    buttons[2] = new TexturedRect(0, 0, 28, 28, texture, 113, 132);
    buttons[3] = new TexturedRect(0, 0, 28, 28, texture, 141, 76);
    buttons[4] = new TexturedRect(0, 0, 28, 28, texture, 141, 104);
    buttons[5] = new TexturedRect(0, 0, 28, 28, texture, 141, 132);

    setRows(recipeCache.getCraftTypes().size());
    setCells(recipeCache.getCraftTypes().size());
  }
  private void initTypes(RecipeCache recipeCache) {
    Set<CraftType> types = recipeCache.getCraftTypes();
    Set<CraftType> filteredTypes = recipeCache.getFilterTypes();

    if (filteredTypes != null) {
      for (CraftType type : types) {
        settings.put(type, 1);
      }

      for (CraftType type : filteredTypes) {
        settings.put(type, 0);
      }
    }
  }
  @Override
  public void mouseMovedRow(int row, int x, int y, boolean inBounds) {
    super.mouseMovedRow(row, x, y, inBounds);

    if (row < recipeCache.getCraftTypes().size() && y > 1 && y < 30 && inBounds) {
      if (x >= (bounds.width() - (3 * 29 + 24)) / 2 + 24
          && x < (bounds.width() - (3 * 29 + 24)) / 2 + 24 + 3 * 29) {
        int relX = (x - ((bounds.width() - (3 * 29 + 24)) / 2 + 24));

        if (relX % 29 != 28) {
          switch (relX / 29) {
            case 0:
              toolTipText = "Show recipes of this type";
              break;

            case 1:
              toolTipText = "Hide recipes of this type";
              break;

            case 2:
              toolTipText = "Show only recipes of this type";
          }
        }
      }
    }
  }
  private void updateFilter() {
    Set<CraftType> set = new HashSet<CraftType>();

    for (CraftType type : settings.keySet()) {
      if (setting(type) == 2) {
        set.add(type);
        recipeCache.setTypes(set);
        return;
      }
    }

    for (CraftType type : recipeCache.getCraftTypes()) {
      if (setting(type) != 1) {
        set.add(type);
      }
    }

    recipeCache.setTypes(set);
  }
  private void set(int row, int setting) {
    Set<CraftType> types = recipeCache.getCraftTypes();

    if (row < types.size()) {
      CraftType type = (CraftType) types.toArray()[row];

      settings.put(type, setting);

      settingChanged(type, setting);
    }
  }
  @Override
  public void renderGridRow(GuiRenderer renderer, int xOffset, int yOffset, int row) {
    Set<CraftType> types = recipeCache.getCraftTypes();

    if (row < types.size()) {
      CraftType type = (CraftType) types.toArray()[row];
      displayBackground.renderRect(renderer, xOffset, yOffset, width(), rowHeight, 0, 0);
      renderer.drawItemStack(type.getDisplayStack(), xOffset + 8, yOffset + 8, false);

      if (hidden(type)) {
        hiddenOverlay.render(renderer, xOffset + 8, yOffset + 8);
      }

      for (int i = 0; i < 3; i++) {
        TexturedRect rect = buttons[i == setting(type) ? i + 3 : i];

        rect.render(
            renderer, xOffset + i * 29 + (bounds.width() - (3 * 29 + 24)) / 2 + 24, yOffset + 2);
      }
    }
  }
 @Override
 public void onChange(RecipeCache cache) {
   setRows(recipeCache.getCraftTypes().size());
 }