マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

バイナリエディタを目指して その5

前回までは表示しかしてなかったので、今回は編集できるようにしてみた。そして、今までスクリーンショットを載せてなかったことに気づいたので、載せておく

それで編集機能を加えるにあたって修正したのはCaretクラスとHexEditorクラス。今の方法だと、キャレットは同じ位置にあっても、上位4bitを修正するか下位4bitを修正するかにわかれる。そのための状態を表す変数は持っていたのだが、状態の切り替えをうまくできていなかった。キャレットの移動時には上位4bit修正するモードにしようと思っていたのだが、Caretクラスの移動に関わるいくつかのメソッドでモードの切り替えが行われていなかった。なので修正した。あとHexEditorは、押されたキーが0〜9またはA〜FならBinaryDocumentに変更を加えるようにした。以下ソース。

まずはCaretクラス

package hexedit.caret;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Color;

public class Caret{
    private int row;
    private int column;
    private int width;
    private boolean isHigh;
    private Highlighter highlighter;

    public Caret(int width){
        row = 0;
        column = 0;
        this.width = width;
        isHigh = true;

        highlighter = new DefaultHighlighter();
        highlighter.setBackgroundColor(new Color(0x60ffCC80, true));
        highlighter.setRoundColor(new Color(0x60ffCC80, true));
    }

    public void nextRow(){
        row++;

        isHigh = true;
    }

    public void beforeRow(){
        if(row > 0)
            row--;

        isHigh = true;
    }

    public void nextColumn(){
        column++;
        if(column >= width){
            column = 0;
            nextRow();
        }

        isHigh = true;
    }

    public void beforeColumn(){
        column--;
        if(column < 0){
            if(row == 0)
                column = 0;
            else
                column = width - 1;

            beforeRow();
        }

        isHigh = true;
    }

    public int getRow(){
        return row;
    }

    public void setRow(int row){
        this.row = row;
        isHigh = true;
    }

    public int getColumn(){
        return column;
    }

    public void setColumn(int column){
        this.column = column;
        isHigh = true;
    }

    public boolean isHigh(){
        return isHigh;
    }

    public void setHigh(boolean isHigh){
        this.isHigh = isHigh;
    }

    public void setBackgroundColor(Color color){
        highlighter.setBackgroundColor(color);
    }

    public void setRoundColor(Color color){
        highlighter.setRoundColor(color);
    }

    public void draw(Graphics g, Rectangle rect){
        highlighter.draw(g, rect);
    }
}

次にHexEditorクラス

package hexedit.editor;

import javax.swing.JComponent;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

import java.awt.Point;
import java.awt.Dimension;
import java.awt.Rectangle;

import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;

import hexedit.document.BinaryDocument;
import hexedit.caret.Caret;

public class HexEditor extends JComponent implements KeyListener{
    private BinaryDocument document;
    private Caret caret;

    private static final String[] DATA_TABLE = new String[]{
        "0", "1", "2", "3", "4", "5", "6", "7",
        "8", "9", "A", "B", "C", "D", "E", "F"
    };

    public HexEditor(){
        this(new BinaryDocument());
    }

    public HexEditor(BinaryDocument document){
        this.document = document;
        caret = new Caret(16);

        int requireColumn = (document.getSize() / 16) + 10;
        setPreferredSize(new Dimension(16 * 26 + 8, requireColumn * 20));

        setFocusable(true);
        addKeyListener(this);
    }

    public void paintComponent(Graphics g){
        g.setFont(new Font("Monospaced", Font.PLAIN, 16));
        g.setColor(Color.BLACK);

        int row = 128;
        int column = 16;

        for(int y = 0; y < row; y++){
            for(int x = 0; x < column; x++){
                int index = (y * column) + x;
                byte data = document.get(index);

                byte high = (byte)((data >> 4) & 0x0F);
                byte low = (byte)(data & 0x0F);

                g.drawString(DATA_TABLE[high], x * 26 + 8, (y + 1) * 20);
                g.drawString(DATA_TABLE[low], (x * 26) + 8 + 8, (y + 1) * 20);
            }
        }

        Rectangle caretRectangle = new Rectangle(caret.getColumn() * 26 + 6, caret.getRow() * 20 + 4, 22, 20);
        caret.draw(g, caretRectangle);
    }

    public void setCaretBackground(Color color){
        caret.setBackgroundColor(color);
    }

    public void setCaretRoundColor(Color color){
        caret.setRoundColor(color);
    }

    public void keyPressed(KeyEvent e){
        switch(e.getKeyCode()){
        case KeyEvent.VK_UP:
            caret.beforeRow();
            break;

        case KeyEvent.VK_DOWN:
            caret.nextRow();
            break;

        case KeyEvent.VK_LEFT:
            caret.beforeColumn();
            break;

        case KeyEvent.VK_RIGHT:
            caret.nextColumn();
            break;

        default:
            break;
        }

        char c = e.getKeyChar();
        int index = caret.getRow() * 16 + caret.getColumn();

        if(c >= '0' && c <= '9'){
            byte data = document.get(index);

            if(caret.isHigh()){
                byte high = (byte)((c - '0') << 4);
                data = (byte)(high + (byte)(data & 0x0F));
                caret.setHigh(false);
            }else{
                byte low = (byte)((c - '0') & 0x0F);
                data = (byte)((byte)(data & 0xF0) + low);
                caret.nextColumn();
            }

            document.set(data, index);
        }

        if(c >= 'a' && c <= 'f'){
            byte data = document.get(index);

            if(caret.isHigh()){
                byte high = (byte)((c - 'a' + 10) << 4);
                data = (byte)(high + (byte)(data & 0x0F));
                caret.setHigh(false);
            }else{
                byte low = (byte)((c - 'a' + 10) & 0x0F);
                data = (byte)((byte)(data & 0xF0) + low);
                caret.nextColumn();
            }

            document.set(data, index);
        }

        if(c >= 'A' && c <= 'F'){
            byte data = document.get(index);

            if(caret.isHigh()){
                byte high = (byte)((c - 'A' + 10) << 4);
                data = (byte)(high + (byte)(data & 0x0F));
                caret.setHigh(false);
            }else{
                byte low = (byte)((c - 'A' + 10) & 0x0F);
                data = (byte)((byte)(data & 0xF0) + low);
                caret.nextColumn();
            }

            document.set(data, index);
        }
        repaint();
    }

    public void keyTyped(KeyEvent e){}
    public void keyReleased(KeyEvent e){}
}