public Dimension getProperSize() {
      Dimension rv = new Dimension();
      BoardState state = curState;

      if (state != null) {
        PuzzleModule pz = pm;

        if (pz != null) {
          Dimension d = pz.getImageSize();
          int w = state.getWidth();
          int h = state.getHeight();

          rv.width = d.width * (w + 2);
          rv.height = d.height * (h + 2);
        }
      }

      return rv;
    }
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);

      BoardState state = curState;

      if (state != null) {
        PuzzleModule pz = pm;

        if (pz != null) {
          Dimension d = pz.getImageSize();
          int imW = d.width;
          int imH = d.height;

          int w = state.getWidth();
          int h = state.getHeight();

          for (int y = 0; y < h; ++y) {
            for (int x = 0; x < w; ++x) {
              String imagePath = pz.getImageLocation(x, y, state);

              Image i = new ImageIcon(imagePath).getImage();

              g.drawImage(i, imW + x * imW, imH + y * imH, null);
            }
          }

          // do headers
          setFont(largeFont);
          for (int x = 0; x < w; ++x) {
            int val = state.getLabel(BoardState.LABEL_TOP, x);
            String imagePath = pz.getImageLocation(val);
            Image i = new ImageIcon(imagePath).getImage();
            g.drawImage(i, imW + x * imW, 0, null);

            val = state.getLabel(BoardState.LABEL_BOTTOM, x);
            imagePath = pz.getImageLocation(val);
            i = new ImageIcon(imagePath).getImage();
            g.drawImage(i, imW + x * imW, imH * (h + 1), null);
          }

          for (int y = 0; y < h; ++y) {
            int val = state.getLabel(BoardState.LABEL_LEFT, y);
            String imagePath = pz.getImageLocation(val);
            Image i = new ImageIcon(imagePath).getImage();
            g.drawImage(i, 0, imH * (y + 1), null);

            val = state.getLabel(BoardState.LABEL_RIGHT, y);
            imagePath = pz.getImageLocation(val);
            i = new ImageIcon(imagePath).getImage();
            g.drawImage(i, imW * (w + 1), imH * (y + 1), null);
          }

          // do grid
          pz.drawGrid(g, new Rectangle(imW, imH, imW * w, imH * h), w, h);
          pz.drawExtraData(
              g,
              state.getExtraData(),
              state.extraDataDelta,
              new Rectangle(imW, imH, imW * w, imH * h),
              w,
              h);
        }
      }
    }
    public void mousePressed(MouseEvent e) {
      BoardState state = curState;

      if (state != null) {
        PuzzleModule pz = pm;

        if (pz != null) {
          Dimension d = pz.getImageSize();
          int imW = d.width;
          int imH = d.height;
          int w = state.getWidth();
          int h = state.getHeight();
          Point p = e.getPoint();

          p.x /= imW;
          p.y /= imH;

          // System.out.println("x = " + p.x + ", y = " + p.y);

          if ((p.x > 0 && p.y > 0) && (p.x <= w && p.y <= h)) {
            --p.x;
            --p.y;

            if (p.x < w && p.y < h) { // p.x and p.y hold the grid point now!
              if (e.getButton() == MouseEvent.BUTTON1) { // left click
                ((Fillapix) pz).directModify(p.x, p.y, state);
              } else { // right click
                BoardImage[] ims = pz.getAllCenterImages();

                int index = ImageChooserDialog.chooseImage(ims);

                if (index != -1) {
                  state.setCellContents(p.x, p.y, ims[index].boardIndex);
                }
              }

              repaint();
            }
          } else {
            boolean[] conditions = {
              (p.x == 0 && p.y > 0 && p.y <= h), // left
              (p.x == w + 1 && p.y > 0 && p.y <= h), // right
              (p.y == 0 && p.x > 0 && p.x <= w), // top
              (p.y == h + 1 && p.x > 0 && p.x <= w) // bottom
            };

            int[] label_direction = {
              BoardState.LABEL_LEFT,
              BoardState.LABEL_RIGHT,
              BoardState.LABEL_TOP,
              BoardState.LABEL_BOTTOM
            };

            int[] label_index = {p.y - 1, p.y - 1, p.x - 1, p.x - 1};

            for (int x = 0; x < conditions.length; ++x) {
              if (conditions[x]) {
                if (e.getButton() == MouseEvent.BUTTON1) { // left click
                  int val = state.getLabel(label_direction[x], label_index[x]);

                  state.setLabel(label_direction[x], label_index[x], pm.getNextLabelValue(val));
                } else {
                  BoardImage[] ims = pz.getAllBorderImages();

                  if (ims.length > 0) {

                    int index = ImageChooserDialog.chooseImage(ims);

                    if (index != -1) {
                      state.setLabel(label_direction[x], label_index[x], ims[index].boardIndex);
                    }
                  }
                }

                repaint();
                break;
              }
            }
          }
        }
      }
    }