private void setupMouseCallbacks() {
        transferHandler = new GridMouseResultsTransferHandler();
        constraintsModel = new GridMouseConstraintsModel(0, 0, maxWidth, maxHeight, CHR_PIXELS_WIDE, CHR_PIXELS_HIGH, PPUConstants.COLUMNS_PER_PATTERN_PAGE, PPUConstants.ROWS_PER_PATTERN_PAGE);

        setTransferHandler(transferHandler);

        if (modelRef == null) {
            // add a generic mouse motion listener to help with tooltips
            addMouseMotionListener(new MouseMotionAdapter() {


                public void mouseMoved(MouseEvent e) {
                    String text = "";
                    int index = constraintsModel.getArrayIndexFromPosition(e.getX(), e.getY());
                    if (index != NES_UI_Constants.INVALID_VALUE) {
                        int xIndex = constraintsModel.getGridXIndexFromPosition(e.getX(), e.getY());
                        int yIndex = constraintsModel.getGridYIndexFromPosition(e.getX(), e.getY());
                        text = "[" + xIndex + "," + yIndex + "] 0x" + ByteFormatter.formatSingleByteInt(index);
                    }
                    // determine position
                    setToolTipText(text);
                }
            });

            return;
        }


        resultsModel = new GridMouseResultsModel(0, 0, PPUConstants.COLUMNS_PER_PATTERN_PAGE, PPUConstants.ROWS_PER_PATTERN_PAGE, modelRef.getCHRModel());
        dragAdapter = new GridMouseInputAndDragAdapter(resultsModel);

        addMouseListener(dragAdapter);
        addMouseMotionListener(dragAdapter);

        dragAdapter.refreshCTD(TransferHandler.NONE, getDropTarget());

        dragAdapter.assignMousePressedCallback(MouseEvent.BUTTON1, new MouseActionCallback() {

            public void doCallback(MouseEvent e, GridMouseResultsModel resultsModel) {
                resultsModel.resetBox();
            }
        });
        dragAdapter.assignMouseClickedCallback(MouseEvent.BUTTON1, new MouseActionCallback() {

            public void doCallback(MouseEvent e, GridMouseResultsModel resultsModel) {
                int index = constraintsModel.getArrayIndexFromPosition(e.getX(), e.getY());
                if (index == NES_UI_Constants.INVALID_VALUE) {
                    return;
                }
                int xIndex = constraintsModel.getGridXIndexFromPosition(e.getX(), e.getY());
                int yIndex = constraintsModel.getGridYIndexFromPosition(e.getX(), e.getY());
                resultsModel.assignIndexX(xIndex);
                resultsModel.assignIndexY(yIndex);
                resultsModel.assignIndex(index);
                processLeftClick(resultsModel.getIndex());
            }
        });
        dragAdapter.assignMouseClickedCallback(MouseEvent.BUTTON3, new MouseActionCallback() {

            public void doCallback(MouseEvent e, GridMouseResultsModel resultsModel) {
                int index = constraintsModel.getArrayIndexFromPosition(e.getX(), e.getY());
                if (index == NES_UI_Constants.INVALID_VALUE) {
                    return;
                }
                int xIndex = constraintsModel.getGridXIndexFromPosition(e.getX(), e.getY());
                int yIndex = constraintsModel.getGridYIndexFromPosition(e.getX(), e.getY());
                resultsModel.assignIndexX(xIndex);
                resultsModel.assignIndexY(yIndex);
                resultsModel.assignIndex(index);
                processRightClick(resultsModel.getIndex());
            }
        });

        dragAdapter.assignMouseMovedCallback(new MouseMoveCallback() {

            public void doMoveCallback(MouseEvent e) {
                String text = "";
                int index = constraintsModel.getArrayIndexFromPosition(e.getX(), e.getY());
                if (index != NES_UI_Constants.INVALID_VALUE) {
                    int xIndex = constraintsModel.getGridXIndexFromPosition(e.getX(), e.getY());
                    int yIndex = constraintsModel.getGridYIndexFromPosition(e.getX(), e.getY());
                    text = "[" + xIndex + "," + yIndex + "] 0x" + ByteFormatter.formatSingleByteInt(index);
                }
                // determine position
                setToolTipText(text);
            }
        });
        dragAdapter.assignMouseDraggedCallback(new MouseDragCallback() {

            private void leftDrag(MouseEvent firstEvent, MouseEvent e, GridMouseResultsModel results) {
                results.assignPatternPage(pageNum);

                int relX = constraintsModel.getGridXIndexFromPosition(e.getX(), e.getY());
                results.assignBoxX(relX);

                int relY = constraintsModel.getGridYIndexFromPosition(e.getX(), e.getY());
                results.assignBoxY(relY);

                System.out.println(e.getX() + "," + e.getY() + " <> " + relX + "," + relY);
                updatePatternTableSelection();

            }

            private void rightDrag(MouseEvent firstEvent, MouseEvent e, GridMouseResultsModel resultsModel) {
                // you can ONLY drag a results box
                if (!resultsModel.isBoxValid()) {
                    return;
                }
                JComponent c = (JComponent) e.getSource();
                TransferHandler handler = c.getTransferHandler();
                //Tell the transfer handler to initiate the drag.
                int action = ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) ? TransferHandler.COPY : TransferHandler.MOVE;
                handler.exportAsDrag(c, firstEvent, action);
                dragAdapter.refreshCTD(action, c.getDropTarget());
            }

            public void doDragCallback(MouseEvent firstEvent, MouseEvent e, GridMouseResultsModel resultsModel) {
                if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
                    leftDrag(firstEvent, e, resultsModel);
                }
                if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) {
                    rightDrag(firstEvent, e, resultsModel);
                }
            }
        });

    }