Gtk2Hsで10進16進変換ツールを作ってみました

HexDec

簡単に10進数と16進数を変換するツールを作ってみました。
使い方を説明します。

  • 数値を入力してエンターを押すと、10進数と16進数を変換します。なお16進数の場合は0xで始めてください。
  • 背景色が、入力文字列が変換可能な場合はライトグリーン、不可能な場合はピンクになります。
  • qまたはQを入力文字列に入れてエンターを押すと、アプリケーションが終了します。
  • スペースを入力文字列に入れてエンターを押すと、入力文字列がクリアされます。

スクリーンショットを右上に載せました。上から16進の0x2904を入力した場合、それを変換した場合、入力ミスがあった場合です。
ソースコードはこちらです。
ファイル: hexdec.hs

import Control.Monad
import Data.Char
import Data.List
import Graphics.UI.Gtk

main :: IO ()
main = do 
  initGUI
  entry  <- entryNew
  entrySetActivatesDefault entry True
  onEditableChanged entry $ validateInput entry
  onEntryActivate entry $ entryActivate entry
  entryModifyBaseOKColor entry

  window <- windowNew
  set window [windowTitle := "HexDec", containerChild := entry]
  onDestroy window mainQuit
  widgetShowAll window
  mainGUI

entryModifyBaseOKColor :: EntryClass ec => ec -> IO ()
entryModifyBaseOKColor entry = 
  widgetModifyBase entry StateNormal $ Color 0xaaaa 0xffff 0xaaaa

entryModifyBaseNGColor :: EntryClass ec => ec -> IO ()
entryModifyBaseNGColor entry = 
  widgetModifyBase entry StateNormal $ Color 0xffff 0xaaaa 0xaaaa

validateInput :: EntryClass ec => ec -> IO ()
validateInput entry = do
  text <- entryGetText entry
  if isValidStirng text
    then entryModifyBaseOKColor entry
    else entryModifyBaseNGColor entry

entryActivate :: EntryClass ec => ec -> IO ()
entryActivate entry = do
  text <- entryGetText entry
  if isValidStirng text
    then convertHexAndDec entry text
    else processSpecialCommand entry text

convertHexAndDec :: EntryClass ec => ec -> String -> IO ()
convertHexAndDec entry text = do
  entrySetText entry $ 
    if isHexString text
      then show $ stringToInteger text
      else integerToHexString $ stringToInteger text

processSpecialCommand :: EntryClass ec => ec -> String -> IO ()
processSpecialCommand entry text
  | any (\c -> c == 'q') text = mainQuit
  | any (\c -> c == 'Q') text = mainQuit
  | any (\c -> c == ' ') text = entrySetText entry ""
  | otherwise = return ()

isValidStirng :: String -> Bool
isValidStirng s =
  if isHexString s
    then all isHexDigit $ tail $ tail s
    else all isDigit s

isHexString :: String -> Bool
isHexString s = "0x" `isPrefixOf` s

integerToHexString :: Integer -> String
integerToHexString n =
  "0x" ++ integerToHexString' "" n
  where
    integerToHexString' :: String -> Integer -> String
    integerToHexString' s n
      | n < 16 = indexToHexString (fromInteger n) ++ s
      | otherwise = integerToHexString'
                      (indexToHexString (fromInteger (n `mod` 16)) ++ s)
                      (n `div` 16)

    indexToHexString :: Int -> String
    indexToHexString i = ["0123456789abcdef" !! i]

stringToInteger :: String -> Integer
stringToInteger s = (read :: String -> Integer) s

ファイル: Makefile

TARGET = hexdec

HC          = ghc
HCFLAGS     = -W -fno-warn-unused-matches --make
HCFLAGS_REL = -optl-mwindows
UPX         = upx
UPXFLAGS    = --overlay=strip --strip-relocs=0
EXE         = .exe

all: $(TARGET)_d$(EXE)
release: clean $(TARGET)$(EXE)

$(TARGET)_d$(EXE): $(TARGET).hs
	$(HC) $(HCFLAGS) $< -o $@

$(TARGET)$(EXE): $(TARGET).hs
	$(HC) $(HCFLAGS) $(HCFLAGS_REL) $< -o $@
	$(UPX) $(UPXFLAGS) $@

clean:
	rm -f $(TARGET)_d$(EXE) $(TARGET)$(EXE) *.o *.hi