# -*- coding: utf-8 -*-
""""
uGaoUtil.py
ユーティリティモジュール
"""
from __future__ import print_function
import uGao.uGaoColorMap
import tempfile
import time
from xml.dom.minidom import parse
import matplotlib.font_manager
import os
import codecs
from matplotlib import __version__ as version
import six
import sys
import matplotlib
matplotlib.rcParams['font.size'] = 10
try:
    from PySide6 import QtCore, QtGui, QtWidgets
    from PySide6.QtGui import QAction
except ModuleNotFoundError:
    try:
        from PySide2 import QtCore, QtGui, QtWidgets
        from PySide2.QtWidgets import QAction
    except ModuleNotFoundError:
        from PySide import QtCore, QtGui
        import PySide.QtGui as QtWidgets
        from PySide.QtGui import QAction

if QtCore.__version__ < '5.0.0':
    matplotlib.use('Qt4Agg')
    if 'backend.qt4' in matplotlib.rcParams:
        matplotlib.rcParams['backend.qt4'] = 'PySide'
    from matplotlib.backends.backend_qt4 import NavigationToolbar2QT
else:
    if matplotlib.get_backend() == "inline":
        pass
    elif not matplotlib.get_backend() == 'Qt5Agg':
        try:
            matplotlib.use('Qt5Agg')
        except:
            matplotlib.use('Agg')

    # removed because recent version of matplotlib shows warning as below
    # "The backend.qt5 rcparam was deprecated in Matplotlib 2.2 and will be removed in 3.1.
    #  In order to force the use of a specific Qt binding, either import that binding first,
    #  or set the QT_API environment variable."
    # if 'backend.qt5' in matplotlib.rcParams:
    #    matplotlib.rcParams['backend.qt5'] = 'PySide2'
    from matplotlib.backends.backend_qt5 import NavigationToolbar2QT
if six.PY2:
    import cPickle as pickle
else:
    import pickle

# メッセージファイル名称定義
MESSAGEFILE = "uGaoMessage.xml"
# MESSAGEFILE = os.path.join(os.path.dirname(__file__),"uGaoMessage.xml")
# マスク値定義(64bit 浮動小数点の最大値)
MASKVALUE = sys.float_info.max / 10000.0
try:
    import Manyo.MLF
    MASKVALUE = Manyo.MLF.MLF_MASKVALUE
except:
    pass

# ログモード時に使用する最小値
MIN_VALUE = 1.0E-25

# Font ファイル
FONT_File = '/usr/share/fonts/ipa-gothic/ipag.ttf'  # CentOS6
WINDOWS_FONT = 'C:\\Windows\\Fonts\\msgothic.ttc'
MAC_FONT = ""

CURRENT_PATH = ""

STRING_TO_REPLACE_SPACE = "<SPACE_REPLACED>"
STRING_TO_REPLACE_LF = "<LINEFEED_REPLACED>"

# Version of matplotlib
v = matplotlib.__version__.split(".")
MATPLOTLIB_VER = "{:02d}{:02d}{:02d}".format(int(v[0]), int(v[1]), int(v[2]))

# Attribute of NavigationToolber has been changed at this version
NAVIGATIONTOOLBAR_CHANGED_VER = "030300" # means "3.3.0"

#########################################


def GetFontProp(fontFile=None):
    """
    フォントプロパティ取得
    @param  fontFile   フォントファイル名
    @retval ファイルのフルパス
    """
    # フォントファイル名が指定されていなければ
    if fontFile is None:
        # プラットフォームが Mac なら
        if sys.platform == "darwin":
            # Mac 用フォントファイル
            fontFile = MAC_FONT
        # プラットフォームはWindows か
        elif os.name == "nt":
            # Windows 用フォントファイル
            fontFile = WINDOWS_FONT
        else:
            # Linux 用フォントファイル
            fontFile = FONT_File
    # フォントファイルは存在するか
    if os.path.exists(fontFile):
        return matplotlib.font_manager.FontProperties(fname=fontFile)
    else:
        # 存在しなければデフォルト
        return matplotlib.font_manager.FontProperties()

#########################################


def SearchPath(fname):
    """
    フルパスの探索
    @param  fname  　ファイル名
    @retval ファイルのフルパス
    """
    if CURRENT_PATH != "":
        fpath = os.path.join(CURRENT_PATH, fname)
        if os.path.isfile(fpath):
            # フルパスを返す
            return fpath
    # カレントディレクトリを取得
    filePath = os.getcwd()
    fpath = os.path.join(filePath, fname)
    # カレントディレクトリに目的ファイルがあるか
    if os.path.isfile(fpath):
        # フルパスを返す
        return fpath
    # > TI [20160217]
    # このファイルと同じディレクトリに目的ファイルがあるか
    fpath = os.path.join(os.path.dirname(__file__), fname)
    if os.path.isfile(fpath):
        # フルパスを返す
        return fpath

    """ Comment Out TI [20160217]
    filePath = ""

    p_path = os.environ.get('PYTHONPATH')
    if p_path is not None:
        p_path_list = p_path.split(os.pathsep)
        path_list = []
        for pp in p_path_list:
            path_list.append( pp )
            path_list.append( os.path.join(pp,"vis") )
        for pp in path_list:
            fp = os.path.normpath( os.path.join( pp,fname ) )
            if os.path.isfile(fp):
                return fp
    """
    return ""

#######################################
#  IFEvtProp
#######################################


class IFEvtProp(object):
    """
    イベントとプロパティ授受用のインターフェイスクラス
    """

    dicInstance = {}

    #########################################
    def __new__(cls, idno=0):
        """
        idno 毎に異なるインスタンスを返すコンストラクタ
        (同一グループ間では共通のインスタンスを使用)
        @param  cls 　クラス
        @param  idno  グループID
          　　　　　　プロッタ番号をIDとして使用
        @retval クラスのインスタンス
        """

        # 指定されたID のクラスインスタンスが生成済みなら
        if idno in cls.dicInstance:
            # 生成済みのインスタンスを返す
            instance = cls.dicInstance[idno]
        else:
            # クラスインスタンスが未生成なら新規に構築
            instance = object.__new__(cls)

        return instance

    #########################################
    def __init__(self, idno=0):
        """
        インターフェイスクラスのコンストラクタ
        @param  idno  グループID
        @retval クラスのインスタンス
        """
        # クラスインスタンスが登録済みなら
        if idno in self.dicInstance:
            # 何もしない
            return

        # クラスインスタンスを登録
        self.dicInstance[idno] = self

        # 登録リストを初期化
        self.InitIF()

    #########################################

    def InitIF(self):
        """
        リスナーリストとプロパティディクショナリの初期化
        @param  無し
        @retval 無し
        """
        # リスナーリストの初期化
        self.listner = []
        # プロパティディクショナリの初期化
        self.property = {}

    #########################################
    def AddListner(self, evtType, func):
        """
        イベントに対するリスナー登録追加
        @param  evtType  イベントタイプ(文字列)
        @param  func     イベント発生時に実行する関数
        @retval index
        """
        index = len(self.listner)
        # イベント発生時に実行する関数を登録
        self.listner.append((evtType, func))
        return index

    #########################################
    def DelListner(self, index):
        """
        リスナー登録削除
        @param  index  削除する登録のインデックス
        @retval 無し
        """
        self.listner.pop(index)

    #########################################
    def AddProperty(self, propKey, func):
        """
        公開するプロパティを登録
        @param  propKey  属性名称(文字列)
        @param  func     プロパティが要求されたときに実行する関数(ラムダ式)
        @retval 無し
        """
        # プロパティを返すラムダ式を登録
        self.property[propKey] = func

    #########################################
    def DelProperty(self, propKey):
        """
        公開プロパティの登録削除
        @param  propKey  属性名称(文字列)
        @retval 無し
        """
        del self.property[propKey]

    #########################################
    def NotifyEvent(self, wid, evtType, value=None):
        """
        イベントに登録されている関数を実行
        (同一イベントに複数登録されている場合は、順番にすべて実行)
        @param  wid      イベント発生元のインスタンス
        @param  evtType  発生したイベントのタイプ(文字列)
        @param  value    イベントの値(省略可)
        @retval 無し
        """
        # リスナーリストから、イベントに登録されているものを探す
        for listner in self.listner:
            evt, func = listner
            # イベントタイプが一致したなら
            if evt == evtType:
                # イベントに登録されている関数を全て実行
                # apply(func, (wid,evtType,value))
                func(*(wid, evtType, value))

    #########################################
    def GetProperty(self, propKey):
        """
        プロパティ取得
        @param  propKey  属性名称(文字列)
        @retval プロパティ
        """
        retval = None
        # プロパティのkey から lambda 式を取得
        try:
            try:
                func = self.property[propKey]
            except:
                raise PlotException(
                    'Common', 'C001', ("Key error:" + propKey, "IFEvtProp:GetProperty"))
            else:
                # プロパティを取得(lambda 式実行)
                try:
                    retval = func()
                except:
                    raise PlotException(
                        'Common', 'C001', ("Lambda execution", "IFEvtProp:GetProperty"))
        except PlotException as ex:
            PlotMessage(None, ex)

        return retval


#######################################
#  Validator
#######################################
class Validator(object):
    """
    入力値チェッククラス
    """
    #######################################

    def __init__(self, frame):
        """
        コンストラクタ
        @param  frame エラーメッセージ表示時の親ウィンドウ
                None の場合は、標準出力に表示
        @retval 無
        """
        self.window = frame

    #######################################################
    def ValidateInteger(self, value, item, minV=None, maxV=None):
        """
        整数の範囲チェック
        @param  Value 確認対象の数値
        @param  item エラーメッセージに入れる項目名(文字列)
        @param  minV  最小値、None の場合は規定無し
        @param  maxV  最大値、None の場合は規定無し
        @retval 評価結果    True : OK,  False: NG
        """
        try:
            try:
                # 整数変換可能か
                num = int(value)
            except:
                raise PlotException('Common', 'C026', (item,))
            # 範囲指定無しか
            if minV is None and maxV is None:
                return True
            # 最小値と最大値が共に指定されているか
            elif minV is not None and maxV is not None:
                # 範囲内か
                if num >= minV and num <= maxV:
                    return True
                else:
                    strR0 = "%d" % minV
                    strR1 = "%d" % maxV
                    raise PlotException('Common', 'C008', (item, strR0, strR1))
            # 最小値だけが指定されているか
            elif minV is not None:
                # 最小値より大きいか
                if num >= minV:
                    return True
                else:
                    strR0 = "%d" % minV
                    raise PlotException('Common', 'C010', (item, strR0))
            # 最大値だけが指定されているか
            elif maxV is not None:
                # 最大値より小さいか
                if num <= maxV:
                    return True
                else:
                    strR1 = "%d" % maxV
                    raise PlotException('Common', 'C012', (item, strR1))

        except PlotException as ex:
            PlotMessage(self.window, ex)
            return False
        return True

    #######################################################
    def ValidatePlus(self, value, item):
        """
        実数の範囲チェック(value > 0)
        @param  value 確認対象の数値
        @param  item エラーメッセージに入れる項目名(文字列)
        @retval 評価結果    True : OK,  False: NG
        """
        try:
            try:
                # 数値に変換可能か
                num = float(value)
            except:
                raise PlotException('Common', 'C027', (item,))
            if num <= 0.0:
                raise PlotException('Common', 'C009', (item, '0.0'))
        except PlotException as ex:
            PlotMessage(self.window, ex)
            return False
        return True

    #######################################################
    def ValidateNumeric(self, value, item, minV=None, maxV=None):
        """
        実数の範囲チェック
        @param  value 確認対象の数値
        @param  item エラーメッセージに入れる項目名(文字列)
        @param  minV  最小値、None の場合は規定無し
        @param  maxV  最大値、None の場合は規定無し
        @retval 評価結果    True : OK,  False: NG
        """
        try:
            try:
                # 数値に変換可能か
                num = float(value)
            except:
                raise PlotException('Common', 'C027', (item,))
            # 範囲指定無しか
            if minV is None and maxV is None:
                return True
            # 最小値と最大値が共に指定されているか
            elif minV is not None and maxV is not None:
                # 範囲内か
                if num >= minV and num <= maxV:
                    return True
                else:
                    strR0 = "%.3f" % minV
                    strR1 = "%.3f" % maxV
                    raise PlotException('Common', 'C008', (item, strR0, strR1))
            # 最小値だけが指定されているのか
            elif minV is not None:
                # 最小値より大きいか
                if num >= minV:
                    return True
                else:
                    strR0 = "%.3f" % minV
                    raise PlotException('Common', 'C010', (item, strR0))
            # 最大値だけが指定されているのか
            elif maxV is not None:
                # 最大値より小さいか
                if num <= maxV:
                    return True
                else:
                    strR1 = "%.3f" % maxV
                    raise PlotException('Common', 'C012', (item, strR1))

        except PlotException as ex:
            PlotMessage(self.window, ex)
            return False
        return True

    #######################################################
    def ValidateRange(self, value0, value1, item, startV, endV, ):
        """
        レンジチェック
        @param  value0 範囲の始値
        @param  value1 範囲の終値
        @param  item エラーメッセージに入れる項目名(文字列)
        @retval 評価結果    True : OK,  False: NG
        """
        try:
            try:
                # 数値に変換可能か
                num0 = float(value0)
                num1 = float(value1)
            except:
                raise PlotException('Common', 'C027', (item,))
            if num0 > num1:
                raise PlotException('Common', 'C009', (endV, startV))

        except PlotException as ex:
            PlotMessage(self.window, ex)
            return False
        return True

    #######################################################
    def ValidateString(self, string, item, minV=None, maxV=None):
        """
        文字列の入力チェック
        @param  string 確認対象の文字列
        @param  item   エラーメッセージに入れる項目名(文字列)
        @param  minV    最小キャラクタ、None の場合は規定無し
        @param  maxV    最大キャラクタ数、None の場合は規定無し
        @retval 評価結果    True : OK,  False: NG
        """
        try:
            try:
                # ASCII 文字列か
                six.u(string)
            except:
                raise PlotException('Common', 'C025', (item,))
            # 範囲指定無しか
            if minV is None and maxV is None:
                return True
            if minV is not None:
                # 最小値より小さいか
                if len(string) < minV:
                    strR0 = "%d" % minV
                    raise PlotException('Common', 'C009', (item, strR0))
            if maxV is not None:
                # 最大値より小さいか
                if len(string) <= maxV:
                    return True
                else:
                    strR1 = "%d" % maxV
                    raise PlotException('Common', 'C012', (item, strR1))
            return True
        except PlotException as ex:
            PlotMessage(self.window, ex)
            return False
        return True

    #######################################################
    def ValidateBoolean(self, value, item):
        """
        ブーリアン値の入力チェック
        @param  value  確認対象
        @param  item   エラーメッセージに入れる項目名(文字列)
        @retval 評価結果  True : OK,  False: NG
        """
        try:
            # True または False か
            if type(value) == bool:
                return True
            else:
                raise PlotException('Common', 'C028', (item, ))
        except PlotException as ex:
            PlotMessage(self.window, ex)
            return False
        return True


#######################################
#  PlotException
#######################################
class PlotException(Exception):
    """
    例外処理用コンテナクラス
    測定条件決定支援処理プログラム内で例外オブジェクトとして使用する
    メッセージ及びエラーコードは当クラスから取得できる
    """

    def __init__(self, category, key, prms):
        """
        コンストラクタ
        @param category:メッセージのカテゴリ
        @param key:メッセージID
        @param prms:編集パラメータ(tupleオブジェクト）

        """
        self.category = category
        self.key = key
        self.prms = prms
        self.code = "00"
        self.detail = "00"

    ################################
    def GetMessage(self):
        """
        メッセージの取得
        @param 無し
        @retval msg:メッセージ
        """
        msg = MessageFile()
        return msg.GetMessage(self.category, self.key, self.prms)

    ################################
    def GetErrorCode(self):
        """
        エラーコードの取得
        @param 無し
        @retval code:エラーコード
        """
        return self.code

    ################################
    def GetDetailCode(self):
        """
        詳細コードの取得
        @param 無し
        @retval detail:詳細コード
        """
        return self.detail

#######################################
#  MessageFile
#######################################


class MessageFile(object):
    """
    MessageFileクラス
    MessageFileの読み込みとMessageの編集を行う
    Singletonクラスとして利用
    """
    instance = None
    lang = 'English'

    ################################
    def __new__(cls, *args):
        """
        Singletonコンストラクタ
        @param 無し
        @retval　無し
        """
        if cls.instance is None:
            cls.instance = object.__new__(cls, *args)
            # メッセージファイル読み込み
            cls.instance.Load()
        return cls.instance

    ################################
    def Load(self):
        """
        MessageFileの読み込み
        @param 　無し
        @retval 無し
        """
        # メッセージファイルの絶対パスを作る
        msgpath = SearchPath(MESSAGEFILE)

        try:
            # メッセージファイルをXML パーサに読み込み
            self.xmlDoc = parse(msgpath)
            self.isRead = True
        except:
            self.isRead = False

    ################################
    def GetMessage(self, parent, key, tap):
        """
        編集されたMessageの取得
        @param parent:メッセージのカテゴリ
        @param key:メッセージID
        @param tap:編集パラメータ(tupleオブジェクト）
        @retval Message
        """
        mser = "Message Code error !! (%s:%s)" % (parent, key)
        # メッセージファイルを読み込み済みか
        if not self.isRead:
            self.Load()
        # メッセージファイルの読み込みに成功しているか
        if self.isRead:
            # 親ノードを取得
            node = self.xmlDoc.getElementsByTagName(parent)
            if node is None:
                return mser
            # 言語ノードを取得
            lang = node[0].getElementsByTagName(self.lang)[0]
            try:
                # メッセージ文字列を取得
                child = lang.getElementsByTagName(key)[0]
            except TypeError:
                return mser
            try:
                # 文字列にタプルで指定された引数を入れこむ
                return child.firstChild.data % (tap)
            except TypeError:
                return "Message Code error !! (type unmatch.)"
        else:
            return 'Message File Read Error!! ( Message.GetMessage() )'

    ################################
    def CloseDoc(self):
        """
        XMLドキュメントの解放
        @param  無
        @retval 無
        """
        if self.isRead:
            self.xmlDoc.unlink()
            self.isRead = False

#######################################
#  PlotMessage
#######################################


class PlotMessage(object):
    """
    各種メッセージの表示クラス
    有効なウィンドウが指定されない場合はコンソールへのテキスト出力
    親ウィンドウが指定されていれば、MessageBoxを表示
    """

    def __init__(self, parent, ex):
        """
        コンストラクタ
        @param parent:親ウィンドウオブジェクト（無ければNoneを指定）
        @param ex:PlotExceptionのインスタンス
        @retval 無し
        """
        msg = ex.GetMessage()
        # MessageBoxを表示する親ウィンドウが無効であればコンソール出力
        if parent is None:
            # traceback.print_stack()
            sys.stdout = codecs.lookup('utf-8')[-1](sys.stdout)
            print(msg)
        else:
            # self.msgBox = QMessageBox(QMessageBox.NoIcon, "hoge", "piyo")
            # [inamura 170609]-->
            # self.msgBox = QMessageBox()
            # self.msgBox.setText(msg)
            # self.msgBox.exec_()
            msg = u"%s" % (msg)
            self.msgBox = QtWidgets.QMessageBox().information(
                parent, u'Message', msg, buttons=QtWidgets.QMessageBox.Ok)

#######################################
#  MakeTempFile
#######################################


class TempFile(object):
    """
    テンポラリファイルクラス
    """
    ###################################################

    def GetTempName(self, ext=""):
        """
        テンポラリファイルの名称を取得
        (モジュール tempfile を使用してファイル名を取得すると、
        消せなくなるため、自分でファイル名を作成)
        @param  無し
        @retval テンポラリファイル名称(フルパス)
                 名称取得に失敗した場合は、None を返す
        """
        # 現在の絶対時間(0.01秒単位)と、プロッタ番号よりテンポラリファイル名を作成
        tsec = int(time.time() * 100.0)
        # tmpf = "tmp%d" % tsec
        tmpf = "tmp%d%s" % (tsec, ext)
        # テンポラリファイルの絶対パスを作成(指定されたテンポラリディレクトリの下)
        tmppath = os.path.join(tempfile.gettempdir(), tmpf)

        # テンポラリファイルの存在チェック
        for i in range(100):
            # 万一同じファイル名があったら、ファイル名を変更
            if os.path.exists(tmppath):
                tmppath = "%s%d%s" % (tmppath, i, ext)
            else:
                # 無ければOK
                break
            if i == 99:
                return None

        return tmppath

    ###################################################
    def MakeTempFile(self, object, temppath):
        """
        Python オブジェクトをシリアライズして
        テンポラリファイルに書き込む
        @param  object    シリアライズするオブジェクト
        @param  temppath  シリアライズしたオブジェクトを書きこむファイル
        @retval  0: 成功、1: テンポラリファイルオープン失敗、2: シリアライズ失敗
        """
        try:
            # テンポラリファイルを開く
            fw = open(temppath, "wb")
        except:
            return 1
        try:
            # オブジェクトをバイナリモードでシリアライズ
            pickle.dump(object, fw, True)
        except:
            # テンポラリファイルをクローズ
            fw.close()
            return 2
        # テンポラリファイルをクローズ
        fw.close()
        # 正常終了
        return 0

    ###################################################
    def ReadTempFile(self, temppath):
        """
        テンポラリファイルを読み込み、デシリアライズかる。
        @param  temppath  シリアライズしたオブジェクトを書きこんだファイル
        @retval  デシリアライズしたデータ、デシリアライズ失敗時は None
        """
        try:
            # テンポラリファイルを読み込む
            fr = open(temppath, "rb")
            # データを復元(デシリアライズ)
            data = pickle.load(fr)
        except:
            return None
        # テンポラリファイルをクローズ
        fr.close()
        # テンポラリファイルを削除
        os.remove(temppath)
        # デシリアライズしたオブジェクトを返す
        return data


##################################################
# classes required from MPlot
# added 170609
##################################################

#######################################
#  ChartToolBar
#######################################
# class ChartToolBar(NavigationToolbar2QT, QtWidgets.QToolBar):
class ChartToolBar(NavigationToolbar2QT):
    """
    matplotlib 画像操作用のツールバーの拡張クラス
    印刷処理追加と、画面設定処理のオーバーライド
    """
    #######################################

    def __init__(self, parent, order):
        """
        コンストラクタ
        @param parent  親クラスのインスタンス
        @param order  イベントディスパッチャのID
        @retval 無
        """
        # self.parent = parent
        # イベント管理クラスのインスタンスを取得
        self.ifi = IFEvtProp(order)
        # 先にスーパークラスのコンストラクタを実行させる
        # NavigationToolbar2QT.__init__(self, parent.canvas)
        # NavigationToolbar2QT.__init__(self,parent.canvas,parent,coordinates=False)
        super(ChartToolBar, self).__init__(
            parent.canvas, parent, coordinates=False)
        # print NavigationToolbar2QT.toolitems
        actions = self.findChildren(QAction)
        for an_action in actions:
            if an_action.text() == 'Customize':
                self.removeAction(an_action)
                break
        # フラグ類の初期化
        self._idle = True
        self.statbar = None
        self.downEvt = None
        self.printingFlag = False
        # イベント格納用リストを準備
        self.evtlst = [None]

    ##################################
    # def _init_toolbar(self):
        """
        ツールバーを作成
        @param 無し
        @retval 無し
        """
        # 先にスーパークラスのツールバーを作る
    #    if version<NAVIGATIONTOOLBAR_CHANGED_VER:
    #        NavigationToolbar2QT._init_toolbar(self)

        # self._parent = self.parent.canvas.getParent()
        # [inamura 210129] removed because the way to print figures using a printer is unknown
        # プリンタのアイコンをツールバーに追加
        # self.setIconSize(QtCore.QSize(24,24))
        # self.addSeparator()
        # self.addAction(QtGui.QIcon("Printer.xpm"), "Print", self.OnPrint)
        # self.addAction(QtGui.QIcon(ImagesXpm().GetQPixmap("Printer")), "Print", self.OnPrint)
        # self.Realize()

    ##################################
    # [inamura 210129] removed because the way to print figures using a printer is unknown
    # def OnPrint(self, evt=None):
    #    """
    #    印刷要求を通知
    #    @param  evt    イベント情報
    #    @retval 無し
    #    """
    #    # 印刷イベント通知
    #    self.ifi.NotifyEvent(self,"print")

    ##################################
    def back(self, evt=None):
        """
        バックワード処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # 先にスーパークラスのバックワード処理処理を実行
        NavigationToolbar2QT.back(self, evt)
        self.evtPoint = self.evtPoint - 1
        # ヒストリ処理
        self._GetHistory()

    ##################################
    def forward(self, evt=None):
        """
        フォワード処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # 先にスーパークラスのフォワード処理処理を実行
        NavigationToolbar2QT.forward(self, evt)
        self.evtPoint += 1
        # ヒストリ処理
        self._GetHistory()

    ##################################
    def _GetHistory(self):
        """
        ヒストリ処理
        @param  無し
        @retval 無し
        """
        # イベント取得
        evt = self.evtlst[self.evtPoint]
        # イベントがNon だったら、Home ボタン押下イベント
        if evt is None:
            # ホームポジションイベントを通知
            self.ifi.NotifyEvent(self, "home")
        else:
            # 表示範囲変更イベントを通知
            self.ifi.NotifyEvent(self, "changexy", self.evtlst[self.evtPoint])

    ##################################
    def home(self, evt=None):
        """
        ホームポジション処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # 先にスーパークラスのホームポジション処理を実行
        try:
            NavigationToolbar2QT.home(self, evt)
        except:
            # ズーム後にプロットを被せたときに発生する例外の抑制
            pass
        # イベントを格納
        self.evtlst.append(None)
        self.evtPoint = len(self.evtlst) - 1
        # ホームポジションイベントを通知
        self.ifi.NotifyEvent(self, "home")

    ##################################
    def back(self, evt=None):
        """
        バックワード処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # スーパークラスのバックワード処理を実行
        try:
            NavigationToolbar2QT.back(self, evt)
        except:
            # ズーム後にプロットを被せたときに発生する例外の抑制
            pass
        # 表示範囲変更イベントを通知
        self.ifi.NotifyEvent(self, "changexy", (self.downEvt, evt))

    ##################################
    def forward(self, evt=None):
        """
        フォワード処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # スーパークラスのフォワード処理を実行
        try:
            NavigationToolbar2QT.forward(self, evt)
        except:
            # ズーム後にプロットを被せたときに発生する例外の抑制
            pass
        # 表示範囲変更イベントを通知
        self.ifi.NotifyEvent(self, "changexy", (self.downEvt, evt))

    ##################################
    def release_zoom(self, evt=None):
        """
        拡大イベント処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # 先にスーパークラスのズーム処理を実行
        NavigationToolbar2QT.release_zoom(self, evt)
        # マウスクリック点がグラフ外であれば
        if self.downEvt is None:
            # 何もしない
            return
        # イベントを格納
        self.evtlst.append((self.downEvt, evt))
        self.evtPoint = len(self.evtlst) - 1
        # 表示範囲変更イベントを通知
        self.ifi.NotifyEvent(self, "changexy", (self.downEvt, evt))

    ##################################
    def release_pan(self, evt=None):
        """
        パンイベント処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # 先にスーパークラスのパン処理を実行
        NavigationToolbar2QT.release_pan(self, evt)
        # マウスクリック点がグラフ外であれば
        if self.downEvt is None:
            # 何もしない
            return
        # イベントを格納
        self.evtlst.append((self.downEvt, evt))
        self.evtPoint = len(self.evtlst) - 1
        # 表示範囲変更イベントを通知
        self.ifi.NotifyEvent(self, "changexy", (self.downEvt, evt))

    ##################################
    def press_zoom(self, evt=None):
        """
        拡大イベント処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # 先にスーパークラスのズーム処理を実行
        NavigationToolbar2QT.press_zoom(self, evt)
        # グラフ内であれば
        if evt.inaxes:
            # ドラッグ開始点のイベントを保存
            self.downEvt = evt
        else:
            self.downEvt = None

    ##################################
    def press_pan(self, evt=None):
        """
        パンイベント処理 (オーバーライド関数)
        @param  evt    イベント情報
        @retval 無し
        """
        # 先にスーパークラスのパン処理を実行
        NavigationToolbar2QT.press_pan(self, evt)
        # グラフ内であれば
        if evt.inaxes:
            # パン開始点のY位置を保存
            self.downEvt = evt
        else:
            self.downEvt = None

    ##################################
    def save(self, evt=None):
        """
        キャンバスに描画されている画像を保存(オーバライド関数)
        @param evt イベント
        @retval 無
        """
        filepath, filt = QtWidgets.QFileDialog.getSaveFileName(
            self.parent, u"Save the image ...", os.getcwd(), filter=u"(*.png *.eps)")
        filepath = str(filepath)
        if filepath == "":
            return
        file_name = os.path.basename(filepath)
        dir_name = os.path.dirname(filepath)
        base, extcode = os.path.splitext(file_name)
        if extcode == "png" or extcode == "eps":
            self.ifi.NotifyEvent(self, "save", filepath)
        """
        # 画像保存用ファイルの絶対パスを取得

        # 保存ファイルタイプの拡張子を取得

        filetypes = "PNG (*.png)|*.png|PS (*.ps)|*.ps|EPS (*.eps)|*.eps"
        # ファイル保存ダイアログを表示
        dlg =wx.FileDialog(self.parent.frame, "Save the image", "", "", filetypes,
                           wx.SAVE|wx.OVERWRITE_PROMPT|wx.CHANGE_DIR)
        # OK であればファイルを保存

        if dlg.ShowModal() == wx.ID_OK:

            # 指定されたパスに日本語が含まれていないかどうかをチェック
            try:
                # wxPython 2.8 on Linux では拡張子を自動付加しない(バグ?)ため
                # 拡張子のチェックを行う。
                path, ext = os.path.splitext(dlg.GetPath())
                # 拡張子が正しく入力されていたらパスを返す
                if ext == ".png"  or ext == ".ps" or ext ==".eps":
                    # パスに日本語が含まれている場合例外が発生
                    try:
                        fname = str(dlg.GetPath())
                    except:
                        raise PlotException('Common','C021',())
                    else:
                        # パスを指定してファイル保存イベントを通知
                        self.ifi.NotifyEvent(self,"save", fname)
                else:
                    # エラーメッセージを表示して保存を行わない
                    raise PlotException('Common','C024',())
            except PlotException as ex:
                PlotMessage(self.parent.frame,ex)
        """

#######################################
#  TraceAtt
#######################################


class TraceAtt(object):
    """
    トレースの属性クラス
    """
    # 線種
    linestyle = ['-', ':', '--', '-.', '']
    # 線幅
    # linewidth = [0.5, 0.6,0.7, 0.8, 1.0, 1.2,1.5, 1.7,2.0,2.5]
    linewidth = [0.5, 0.6, 0.7, 0.8, 1.0, 1.2, 1.5, 1.7, 2.0,
                 2.5, 3.0, 3.6, 4.4, 5.2, 6.4, 7.6, 9.0, 11.0, 14.0, 16.0]
    # 色
    color = ['*', 'b', 'g', 'r', 'c', 'm', 'y', 'k']
    # マーカの種類
    marker = ['', '.', 'o', 's', 'v', 'd', '+', 'x']
    # マーカサイズ
    # msize = [2.0, 2.8, 3.5, 4.0, 4.3,4.7,5.1,5.7, 6.4,7.0]
    msize = [2.0, 2.4, 2.8, 3.3, 3.8, 4.4, 5.0, 5.6, 6.2, 7.0,
             8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.5, 16.0, 18.0, 20.0]
    # キャップサイズ
    csize = [0.5, 0.7, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 5.0]
    # marker face status
    mface = ['fill', 'none']
    # デフォルトプロット属性
    # defaultTraceAttr = {"ls":"-","hs":0, "lw":5,"lc":"*","mk":"","ms":5,"mc":"*","eb":0,"es":5,"ec":"*"}
    # New Default: no line, circle mark with error bar.
    # defaultTraceAttr = {"ls":"","hs":0, "lw":5,"lc":"*","mk":"o","ms":5,"mc":"*","eb":1,"es":5,"ec":"*"}
    # New Default: added marker face option "fill" or "none"
    defaultTraceAttr = {"ls": "", "hs": 0, "lw": 5, "lc": "*", "mk": "o",
                        "ms": 5, "mc": "*", "eb": 1, "es": 5, "ec": "*", "mf": "fill"}
    # 属性とデータ型
    attrType = {'autox': 3, 'autoy': 3,
                'x0': 2, 'x1': 2, 'y0': 2, 'y1': 2,
                'overlay': 3,
                'offsetx': 1, 'offsety': 1,
                'log': 3,
                'tracenum': 1,
                'page': 1,
                'title1': 0, 'title2': 0,
                'xlabel': 0, 'ylabel': 0,
                'datanum': 1,
                'traceattrs': 4}

#######################################
#    Default of FastPlot Attributes
#    [inamura 120131]
#######################################


class DefaultFastPlotAtt(object):
    """
    Keep Default Attributes for FastPlot
    """

    def __init__(self):
        self.FileName = ".fastplotdefault.ini"
        self.HomeDir = os.environ["HOME"]
        self.TraceAttKeys = list(TraceAtt().defaultTraceAttr.keys())
        self.DialogPathKeys = ["OPENPATH", "SAVEPATH"]

        if os.path.exists(os.path.join(self.HomeDir, "ana", "xml")):
            self.Path = os.path.join(self.HomeDir, "ana", "xml", self.FileName)
        else:
            self.Path = os.path.join(self.HomeDir, self.FileName)
        if not os.path.exists(self.Path):
            print("Make new initial file.")
            Tattr = TraceAtt().defaultTraceAttr.copy()
            for key in self.DialogPathKeys:
                Tattr[key] = self.HomeDir
            self._save(Tattr)

    def _save(self, attrs):
        try:
            fd = open(self.Path, "wb")
        except:
            print("Cannot open", self.Path)
            raise OSError()
        pickle.dump(attrs, fd)
        fd.close()

    def _load(self):
        try:
            fd = open(self.Path, "rb")
        except:
            print("Cannot open", self.Path)
            return None
        try:
            ret = pickle.load(fd)
            fd.close()
        except:
            fd.close()
            print("MPlot >> Failed to encode setting file ({}). MPlot replaces it with default setting.".format(self.Path))
            Tattr = TraceAtt().defaultTraceAttr.copy()
            for key in self.DialogPathKeys:
                Tattr[key] = self.HomeDir
            self._save(Tattr)
            fd = open(self.Path, "rb")
            ret = pickle.load(fd)
            fd.close()
        return ret

    def savePlotAtt(self, trace_att):
        load_dic = self._load()
        for key in trace_att:
            load_dic[key] = trace_att[key]
        self._save(load_dic)

    def loadPlotAtt(self):
        load_dic = self._load()
        ret = TraceAtt().defaultTraceAttr.copy()
        for key in load_dic:
            if not (key in self.DialogPathKeys):
                ret[key] = load_dic[key]
        return ret

    def loadPath(self):
        load_dic = self._load()
        ret = {}
        for key in self.DialogPathKeys:
            if key in load_dic:
                ret[key] = load_dic[key]
            else:
                ret[key] = self.HomeDir

        return ret

    def savePath(self, key, path):
        if not (key in self.DialogPathKeys):
            return
        load_dic = self._load()
        load_dic[key] = path
        self._save(load_dic)


#######################################
#  VerHandleMatPlot
#######################################
class VerHandlePlotLib(object):
    """
    matplotlib のバージョンの違いを吸収する
    """
    ###################################################

    def __init__(self):
        """
        コンストラクタ、matplotlib のバージョンを取得
        """
        # matplotlib のバージョン取得
        vers = version.split('.')
        self.verNo = int(vers[0]) * 1000 + int(vers[1]) * 10 + int(vers[0])

    ###################################################
    def IfVerUp(self, ver):
        """
        テンポラリファイルの名称を取得
        (モジュール tempfile を使用してファイル名を取得すると、
        消せなくなるため、自分でファイル名を作成)
        @param  (int) バージョン番号　
        　　　　　　　　　　　　　　0.90.0 以上であれば、900
                      1.01.1 以上であれば　1011
        @retval True : 指定されたバージョン以上
        　　　　　　　　False: 指定されたバージョン未満
        """
        if self.verNo >= ver:
            return True
        else:
            return False

    ###################################################
    def GetSubPlotPos(self, sbplot):
        """
        サブプロッタの位置情報取得
        @param  sbplot subplot(0.98未満)トまたは AxisPlot (0.98 以上)
        　　　　       　　　　       のインスタンス
        @retval [x0, x1, x, y] のリスト
        """
        if self.IfVerUp(980):
            pos = sbplot.get_position()
            posp = pos.get_points()
            return [posp[0, 0], posp[0, 1], posp[1, 0] - posp[0, 0], posp[1, 1] - posp[0, 1]]
        else:
            return sbplot.get_position()


#######################################
#  ConvertEC
#######################################
class ConvertEC(object):
    """
    エレメントコンテナ変換クラス
    Manyo-Lib のエレメントコンテナを、FastPlot 用のデータに
    変換する。
    """
    ###################################################

    def ConvertEC(self, ec):
        """
        エレメントコンテナ変換
        @param  ec  エレメントコンテナのインスタンス
        @retval x, y, er のアレイ、x軸単位、Y軸単位、ヘッダーディクショナリのタプル
        　　　　　　　　変換できなかった場合は、None を返す
        """
        try:
            # X値リストを取得
            xx = ec.PutXList()
            if ec.PutHeader().CheckKey("Xkey") == 0:
                ec.AddToHeader("Xkey", ec.PutXKey())
            else:
                ec.PutHeaderPointer().OverWrite("Xkey", ec.PutXKey())

            # Y値リストを取得
            yy = ec.PutYList()
        except:
            # Manyo-Lib ではない?
            try:
                ec[1][1]
            except:
                # プロット可能なデータではない
                return None
            else:
                # プロット可能なデータなら、元データをそのまま返す
                return ec

        try:
            # エラーリストを取得
            er = ec.PutEList()
        except:
            # エラー無しのヒストグラム
            er = None

        # ヘッダーディクショナリ作成
        header = self._MakeHeaderDic(ec)

        # X軸とY軸の単位文字列を取得
        xunit = ""
        yunit = ""
        try:
            xunit = ec.PutUnit(ec.PutXKey())
            yunit = ec.PutUnit(ec.PutYKey())
        except:
            pass

        if (er is not None):
            for i in range(len(yy)):
                if er[i] < 0:
                    yy[i] = MASKVALUE
                    er[i] = 0.0
        return [xx, yy, er, header, xunit, yunit]

    ###################################################
    def _MakeHeaderDic(self, ec):
        """
        エレメントコンテナ変換
        @param  ec  エレメントコンテナのインスタンス
        @retval ヘッダーディクショナリ
        """
        # ヘッダーの辞書を用意
        header = {}
        try:
            # ヘッダーを取得
            ech = ec.PutHeader()
            # ヘッダーストリングを取得
            work = ech.DumpToString()
        except:
            # 空のヘッダーを返す
            return header
        # ヘッダーストリングを '#' 区切りで分解
        head_ss = work.split('#')

        # 整数型のキーを取得
        if head_ss[2] != "None":
            intKey_num = int(head_ss[0])
            intKey = head_ss[2].split('\\,')
            if len(intKey) != intKey_num:
                intKey = head_ss[2].split(',')
            i = 0
            # キーの数だけ値を取得し、文字列に変換してディクショナリに格納
            for key in intKey:
                head_sV = "%d" % ech.PutInt4(i)
                header[key] = head_sV
                i += 1

        # 実数型のキーを取得
        if head_ss[8] != "None":
            dblKey_num = int(head_ss[6])
            dblKey = head_ss[8].split('\\,')
            if len(dblKey) != dblKey_num:
                dblKey = head_ss[8].split(',')
            i = 0
            # キーの数だけ値を取得し、文字列に変換してディクショナリに格納
            for key in dblKey:
                head_sV = "%.6f" % ech.PutDouble(i)
                header[key] = head_sV
                i += 1

        # 文字列型のキーを取得
        if head_ss[14] != "None":
            head_sKey_num = int(head_ss[12])
            head_sKey = head_ss[14].split('\\,')
            if len(head_sKey) != head_sKey_num:
                head_sKey = head_ss[14].split(',')
            i = 0
            # キーの数だけ値を取得しディクショナリに格納
            for key in head_sKey:
                header[key] = ech.PutString(i)
                i += 1

        # Get Keys of Vector
        index_h = 18

        # Int4Vector
        num = int(head_ss[index_h])
        if num != 0:
            index_h = index_h + 2
            ivKey = head_ss[index_h].split('\\,')
            if len(ivKey) != num:
                ivKey = head_ss[index_h].split(',')
            i = 0
            for key in ivKey:
                index_h = index_h + 2
                if int(head_ss[index_h]) < 7:
                    iv = ech.PutInt4Vector(i)
                    head_s = ''
                    for k in range(iv.size()):
                        head_s = head_s + ("%.3f" % iv[k])
                        if k != (iv.size() - 1):
                            head_s = head_s + ","
                    header[key] = head_s

                i = i + 1
                index_h = index_h + 2

        index_h = index_h + 2
        # DoubleVector
        num = int(head_ss[index_h])
        if num != 0:
            index_h = index_h + 2
            dvKey = head_ss[index_h].split('\\,')
            if len(dvKey) != num:
                dvKey = head_ss[index_h].split(',')
            i = 0
            for key in dvKey:
                index_h = index_h + 2
                if int(head_ss[index_h]) < 7:
                    dv = ech.PutDoubleVector(i)
                    head_s = ''
                    for k in range(dv.size()):
                        head_s = head_s + ("%.3f" % dv[k])
                        if k != (dv.size() - 1):
                            head_s = head_s + ","
                    header[key] = head_s

                i = i + 1
                index_h = index_h + 2
        else:
            index_h = index_h + 2

        return header


#######################################
#  ImagesXpm
#######################################
class ImagesXpm(object):
    """
    Image data for QT
    """
    instance = None

    def __new__(cls, *args):
        """
        Singletonコンストラクタ
        @param  *args 可変引数(無し)
        @retval クラスのインスタンス
        """
        if cls.instance is None:
            # クラスインスタンスが未生成なら新規に構築
            cls.instance = object.__new__(cls, *args)
        return cls.instance

    #########################################
    def GetQPixmap(self, iname):
        if iname in self.imageData:
            return QtGui.QPixmap(self.imageData[iname])
        else:
            return None

    imageData = {
        'MainIcon': ["32 32 255 2", "6  c #C32727", "*  c #C13030", "a  c #B72525", "A. c #AF1111", "a. c #EEB700",
                     "e. c #78CF08", "AX c #81C70E", "sX c #75C50B", ">. c #905B08", "M  c #AB201E", "iX c #FAE212",
                     "2. c #CA6505", "+. c #F6C200", "E. c #FED003", "U  c #EC6363", "7X c #6BBA08", "O  c #E44F4F",
                     "o. c #A41F1D", "b. c #FECD00", "q  c #BF302F", "f. c #72B508", "t. c #B21515", "1  c #BF2D2D",
                     "'. c #85DB11", "r. c #9A3408", "q. c #76CC08", "S  c #A91D19", " . c #93360C", "oX c #AAF42E",
                     "@  c #9D150A", "<X c #70B507", "b  c #BD3030", "L. c #8FE019", "v  c #C42B2B", "$  c #B82929",
                     "1. c #B12514", "KX c #C58727", "%. c #75B607", "6. c #EAB400", "=. c #71C208", "BX c #DDA200",
                     "1X c #A3F029", "~. c #FAD006", "yX c #9BB005", "V  c #D52B2B", "i  c #9B150A", "=  c #BB2D25",
                     "&X c #DDA207", "CX c #E7A700", "hX c #ECAB01", "H  c #E55050", "vX c #E4A00E", "=X c #7FB807",
                     "W. c #FFCE00", "]  c #F2BC00", "qX c #E0A600", "u  c #AF2827", "Z. c #7BC107", "K. c #97E521",
                     "h. c #6FBF08", "K  c #E35050", "gX c #C88527", "@. c #F5C000", "0X c #FCEA15", "|. c #FFF419",
                     ":. c #7CA507", "SX c #8BDA13", "6X c #9AE921", "u. c #FDCB00", "n  c #A31A15", "%  c #B42323",
                     "R. c #FEDE0C", "l. c #7AD109", "I. c #8BDA19", "J  c #EE6868", ";X c #BAFE3B", "%X c #FEDB0A",
                     "p. c #F8C400", "`. c #7DD809", "s. c #EBB200", "l  c #DF5656", "g  c #BC3131", "^. c #DEA309",
                     "9. c #6DBC08", "L  c #AD1F1C", ")  c #A11D1A", "B  c #E95E5E", ",  c #BE2525", "0  c #B72727",
                     "JX c #EDA903", "F  c #D42F2F", "}. c #FED506", "E  c #D93333", ":  c #B72424", "C  c #D42C2C",
                     "d. c #D49810", "*. c #70C009", "wX c #DCA000", "X. c #C82727", "p  c #9F1A14", "<  c #BC2525",
                     "lX c #EFC609", "-X c #DCA007", "-. c #73C708", "fX c #75C10B", "zX c #F2D00D", "y  c #CD2828",
                     "9  c #C12626", "W  c #B52424", "+X c #A0EE26", ".  c #981304", "y. c #B52121", "OX c #BBFF3B",
                     "G  c #EF6969", "x  c #D22929", "7  c #C62727", ">  c #BA2525", " X c #DFA407", "4  c #B32727",
                     "t  c #CB2828", "r  c #BF2626", "j. c #79D209", "0. c #71C408", "8. c #6EBA09", "!  c #A71F1D",
                     "s  c #D02929", "3. c #FCC900", "x. c #A9130E", "uX c #F8D80D", "*X c #A8F32C", "9X c #FBE211",
                     "8  c #C92828", "J. c #6EB407", "h  c #A51F17", "C. c #7CD609", "&. c #85CE10", "f  c #CE2929",
                     "@X c #9CEB22", "!. c #FEE913", "D. c #B7CA0F", "MX c #C88724", "XX c #6FC108", "_. c #B7FC39",
                     "d  c #D32A2A", "4. c #FAC600", ";  c #D44040", "m  c #991102", "NX c #E7A30C", "aX c #83CE10",
                     "[. c #FFF61A", "c. c #B11818", "v. c #AA170E", "]. c #8EBA06", "V. c #7AD309", "N. c #6AB708",
                     "{  c #DEAB16", "#X c #84DB10", "^  c #E1B210", "dX c #7AD00A", "P  c #971102", "nX c #72C20A",
                     "Y  c #EE6767", "S. c #8F520A", "I  c #DE3F3F", ";. c #75C908", "LX c #A7F41D", "2X c #87B606",
                     "$X c #80B807", "Q. c #FED707", "g. c #68B407", "k  c #A61D19", "/. c #C98825", "4X c #D4970A",
                     "<. c #DA4848", "}  c #7CC10B", "|  c #77BD0B", "`  c #9F1913", "GX c #DE9C11", "k. c #7BD409",
                     "3X c #E4AA00", "ZX c #C78826", "3  c #A9211E", "M. c #D79B0F", "5. c #ECB500", "jX c #E4A700",
                     "Q  c #A91E1B", ",. c #B52020", "5  c #BA2424", ".. c #AE2222", "(. c #70B608", "{. c #FFD807",
                     "H. c #DA9F0C", "R  c #E24A4A", "T  c #DA3636", "&  c #B32323", "F. c #FBE714", "B. c #79D108",
                     "   c None", "tX c #69B507", "Z  c #DD4343", "IX c #C58524", "xX c #E2A700", "5X c #C58529",
                     "8X c #94B305", "e  c #AC2222", "bX c #7DC20C", "n. c #F2C002", "X  c #960F02", "O. c #B95107",
                     "U. c #97BA06", "HX c #ECA900", "T. c #FEEB14", "_  c #E85B5B", "Y. c #FDD507", ":X c #86DD12",
                     "i. c #FAC800", "eX c #CB8D19", "w. c #77CE08", "[  c #EBBF09", "VX c #E0A400", "mX c #85CA10",
                     "pX c #D8990B", "/  c #C88629", "+  c #991309", "o  c #DE4A4A", ">X c #E8AF00", "cX c #EAA902",
                     "m. c #F6D40C", "~  c #DB3A3A", "w  c #9E170E", "rX c #90E21A", "G. c #F0BD03", "FX c #8DD511",
                     "$. c #F3C400", "#. c #F0BA00", "7. c #CE911A", "z  c #DC4D4D", ".X c #C68625", "A  c #D43939",
                     ",X c #D6990A", "#  c #CD3B3A", "j  c #971000", "N  c #E14E4E", "2  c #D74342", "P. c #9FEB27",
                     "-  c #971004", "). c #A4EF2A", "D  c #AD201E", "c  c #D62A2A", "'  c #F3BE00", "(  c #96750C",
                     "PX c #A2EF1C", "kX c #E6AC00", "z. c #925808", "DX c #89D812",
                     "                            . X                                 ",
                     "                            o O +                               ",
                     "                      @ # $ % % & * = -                         ",
                     "                    = ; : > , , < > 1 2                         ",
                     "                3 4 5 , 6 7 8 8 7 7 9 , 0 q                     ",
                     "              w e & r 9 8 t y y y y 7 6 > % u i                 ",
                     "              p a , 7 t s s d d d s f t 9 , g h                 ",
                     "            j k l z t y x d c c d d s f 7 v b n                 ",
                     "            m M r 6 N B V c c c c c C Z A 7 : S                 ",
                     "            m D 9 7 s F G H c c c c J K y 7 5 L                 ",
                     "            P D 9 7 s x c I G G G U d d y 7 > L                 ",
                     "            P D 9 7 s s c c G G Y T d d y 7 > L                 ",
                     "            j M , 6 y s d c R G E c d s 8 6 W Q                 ",
                     "            j ! > 9 t f d d ~ G c d s f 7 9 & k ^ /             ",
                     "            ( ) & 5 6 8 f s s _ s s y 8 9 > e ` ' ] [ {         ",
                     "          } |  ...% 9 6 t y f K y y X.6 > W o.O.+.@.#.$./       ",
                     "    %.&.*.=.-.;.:.>.,.5 9 9 7 <.6 6 , 5 1.2.3.3.4.4.+.' 5.6.7.  ",
                     "    8.9.0.-.q.w.e.e.r.t.> < , # , < y.t.3.u.u.u.3.i.p.+.a.s.d.  ",
                     "f.g.h.0.q.w.j.j.k.k.j.l.z.x.....c.v.4.u.u.b.b.b.u.u.4.p.n.m.M.  ",
                     "f.N.=.-.w.B.V.k.C.C.k.k.B.Z.A.A.S.D.3.u.b.b.b.b.u.u.4.4.F.G.H.  ",
                     "J.9.-.K.L.V.C.C.C.C.C.C.k.j.P.I.h.U.Y.T.R.E.W.b.b.Q.!.~.' #.^./.",
                     "(.h.;.w.)._.C.C.`.`.C.C.'._.w.;.h.].3.u.[.[.{.}.|.[.3.4.' #. X.X",
                     "(.XX;.w.k.C.oXOX+X@XoXOX#Xk.e.q.XX$X3.u.u.%X[.[.Q.u.4.p.] a.&X.X",
                     "(.XX;.w.k.C.C.*XOXOXOX+XC.k.e.q.XX=X4.3.u.u.[.[.u.3.4.p.#.5.-X.X",
                     "(.h.;.w.j.k.C.C.;XOX:XC.C.V.w.;.XX=Xp.p.i.3.[.[.4.4.+.' 5.>X,X.X",
                     "<X9.-.q.j.k.C.C.1XOXC.C.k.j.w.;.h.2X@.+.p.4.[.[.p.p.' #.>X3X4X5X",
                     "J.N.=.-.e.B.k.k.6XOXC.k.j.e.;.0.7X8Xa.#.' @.9X0X' ] 5.s.qXwXeX  ",
                     "J.g.XX0.q.w.j.j.rXOXV.l.e.w.0.XXtXyXs.5.a.#.uXiXa.a.>X3XwXpX    ",
                     "    aXsX0.-.q.w.dXOXw.w.;.0.h.fX  gXhXjX3XkXlXzX3XxXcXvX        ",
                     "      bXnX0.-.;.q.OX;.;.0.XXmX      MXNXBXVXVXVXBXCXZX          ",
                     "          AXSXh.XXXXh.DXFX              MXGXHXJXKX              ",
                     "            } LX7X7XPXbX                    IX                  "
                     ],
        'Printer': ["18 18 6 1", ". c Black", "X c #FFFFFF", "O c #808080", "+ c #FFFF00", "  c #ECE9D8", "o c #C0C0C0",
                    "                  ",
                    "                  ",
                    "      .........   ",
                    "     .XXXXXXXX.   ",
                    "     .X.....X.    ",
                    "    .XXXXXXXX.    ",
                    "    .X.....X....  ",
                    "   .XXXXXXXX.o.o. ",
                    "  ..........o.o.. ",
                    " .oooooooooo.o.o. ",
                    " .............oo. ",
                    " .ooooooOOOoo.o.  ",
                    " .oooooo+++oo...  ",
                    " .............o.  ",
                    "  .ooooooooo.o.   ",
                    "   ...........    ",
                    "                  ",
                    "                  "
                    ],
        'Pen': ["24 24 10 1",
                "# c Black", "% c #808080", ". c #CCCC99", "+ c #CC66CC", "o c #FFCCFF", "  c #804000",
                "$ c #C0C0C0", "X c #333333", "@ c #FFFFCC", "O c #FF99FF",
                "                        ",
                " .................XXX.. ",
                " ................XoXOX. ",
                " ...............XoXOOXX ",
                " ..............XoXOOX+X ",
                " .............XoXOOX++X ",
                " ............XoXOOX++X. ",
                " ...........XoXOOX++X.. ",
                " ..........XXXOOX++X... ",
                " .........X@@@XX++X.... ",
                " .....#.#.X@@@.X+X..... ",
                " ......#..XX@..X#...... ",
                " ......#..XX#..#....... ",
                " .....#.#.X####........ ",
                " ......$$.............. ",
                " .....##%.............. ",
                " ....####$............. ",
                " ....#%.#%............. ",
                " ...##$.##$............ ",
                " ...#%...#%............ ",
                " ..##$...##$........... ",
                " ..#%.....#%$.......... ",
                " ###$.....###%......... ",
                "                        "
                ],
        'Left': ["24 24 6 1",
                 "X c Black", "O c #808080", "o c #804000", "+ c #808000", ". c #E7E7E7", "  c #808040",
                 "                        ",
                 " ...................... ",
                 " ...................... ",
                 " .................X.... ",
                 " ...............ooXO... ",
                 " .............oo++XO... ",
                 " ...........oo++++XO... ",
                 " .........oo++++++XO... ",
                 " .......oo++++++++XO... ",
                 " .....oo++++++++++XO... ",
                 " ...oo++++++++++++XO... ",
                 " ..X++++++++++++++XO... ",
                 " ..OXX++++++++++++XO... ",
                 " ....OXX++++++++++XO... ",
                 " ......OXX++++++++XO... ",
                 " ........OXX++++++XO... ",
                 " ..........OXX++++XO... ",
                 " ............OXX++XO... ",
                 " ..............OXXXO... ",
                 " ................OXO... ",
                 " .................OO... ",
                 " ...................... ",
                 " ...................... ",
                 "                        "
                 ],
        'Right': ["24 24 6 1",
                  "X c Black", "o c #808080", "O c #804000", "+ c #808000", ". c #E7E7E7", "  c #808040",
                  "                        ",
                  " ...................... ",
                  " ...................... ",
                  " ...X.................. ",
                  " ..oXOO................ ",
                  " ..oX++OO.............. ",
                  " ..oX++++OO............ ",
                  " ..oX++++++OO.......... ",
                  " ..oX++++++++OO........ ",
                  " ..oX++++++++++OO...... ",
                  " ..oX++++++++++++OO.... ",
                  " ..oX++++++++++++++X... ",
                  " ..oX++++++++++++XXo... ",
                  " ..oX++++++++++XXo..... ",
                  " ..oX++++++++XXo....... ",
                  " ..oX++++++XXo......... ",
                  " ..oX++++XXo........... ",
                  " ..oX++XXo............. ",
                  " ..oXXXo............... ",
                  " ..oXo................. ",
                  " ..oo.................. ",
                  " ...................... ",
                  " ...................... ",
                  "                        "
                  ],
        'Pin': ["24 24 8 1",
                "@ c Black", "# c #808080", ". c #DEDCDA", "o c #FF80FF", "O c #800000", "X c #FF0000",
                "+ c #C0C0C0", "  c #808000",
                "                        ",
                " ...............X...... ",
                " ...............XX..... ",
                " ..............XoXX.... ",
                " .............XoXXOO... ",
                " ..........XXXoXXO+.... ",
                " ...........XXXXO+..... ",
                " ............XXO+...... ",
                " ...........@+XO....... ",
                " ..........@+..O....... ",
                " .....@.@.@+........... ",
                " ......@............... ",
                " ......@............... ",
                " .....@.@.............. ",
                " ......++.............. ",
                " .....@@#.............. ",
                " ....@@@@+............. ",
                " ....@#.@#............. ",
                " ...@@+.@@+............ ",
                " ...@#...@#............ ",
                " ..@@+...@@+........... ",
                " ..@#.....@#+.......... ",
                " @@@+.....@@@#......... ",
                "                        "
                ],
        'Xlabel': ["24 24 18 1",
                   "@ c Black", "o c #D2CFCE", ", c #808080", "& c #7B7978", "$ c #92908F", ": c #AEABAB",
                   "# c #434242", "O c #B6B3B2", "+ c #C5C2C1", "= c #5B5A59", "; c #9C9A99", "> c #C0C0C0", "% c #A5A3A2",
                   "* c #6C6B6A", "- c #CBC9C8", ". c #DFDCDB", "X c #BDBBBA", "  c #808040",
                   "                        ",
                   " ...................... ",
                   " .........XX..oO+...... ",
                   " ........o@@O.#@$...... ",
                   " .........@@%&@&....... ",
                   " .........*@@@=........ ",
                   " .........&@@@-........ ",
                   " .........;@@O......... ",
                   " ........-@@@+......... ",
                   " ........@@@@:......... ",
                   " .......=@$@@%......... ",
                   " ......$@=.&@&......... ",
                   " .....;@@..$@=......... ",
                   " ...................... ",
                   " ........>@>........... ",
                   " ........@@,........... ",
                   " .......@@@@>.......... ",
                   " .......@,>@,.......... ",
                   " ......@@>.@@>......... ",
                   " ......@,...@,......... ",
                   " .....@@>...@@>........ ",
                   " .....@,.....@,>>...... ",
                   " ...@@@>.....@@@,...... ",
                   "                        "
                   ],
        'Ylabel': ["24 24 17 1",
                   "@ c Black", "X c #D2CFCE", "> c #808080", "* c #7B7978", "# c #92908F", "- c #434242",
                   "o c #B6B3B2", "O c #C5C2C1", "$ c #5B5A59", ": c #C0C0C0", "; c #878584", "= c #A5A3A2",
                   "& c #6C6B6A", "% c #CBC9C8", ". c #DFDCDB", "+ c #BDBBBA", "  c #808040",
                   "                        ",
                   " ........XoO...O+...... ",
                   " ........O@@X.#@$...... ",
                   " ........%@@Oo@@....... ",
                   " .........@@#@@%....... ",
                   " .........&@@@o........ ",
                   " .........*@@=......... ",
                   " .........#@*.......... ",
                   " .........-@o.......... ",
                   " ........+@@........... ",
                   " ........#@;........... ",
                   " ........-@o........... ",
                   " ........++............ ",
                   " ...................... ",
                   " ........:@:........... ",
                   " ........@@>........... ",
                   " .......@@@@:.......... ",
                   " .......@>:@>.......... ",
                   " ......@@:.@@:......... ",
                   " ......@>...@>......... ",
                   " .....@@:...@@:........ ",
                   " .....@>.....@>::...... ",
                   " ...@@@:.....@@@>...... ",
                   "                        "
                   ],
        'XYlabel': ["24 24 24 1",
                    "@ c Black", "3 c #D9D9D9", "o c #D2CFCE", "5 c #808080", "* c #7B7978", "$ c #92908F",
                    ": c #AEABAB", "# c #434242", ", c #A7A7A7", "O c #B6B3B2", "+ c #C5C2C1", "% c #5B5A59",
                    "; c #9C9A99", "< c #9A9A9A", "1 c #C7C7C7", "> c #C0C0C0", "2 c #878584", "& c #A5A3A2",
                    "- c #6C6B6A", "4 c #B2B2B2", "= c #CBC9C8", ". c #DFDCDB", "X c #BDBBBA", "  c #808040",
                    "                        ",
                    " ...................... ",
                    " ....XX..oO+..oO+...+X. ",
                    " ...o@@O.#@$..+@@o.$@%. ",
                    " ....@@&*@*...=@@+O@@.. ",
                    " ....-@@@%.....@@$@@=.. ",
                    " ....*@@@=.....-@@@O... ",
                    " ....;@@O......*@@&.... ",
                    " ...=@@@+......$@*..... ",
                    " ...@@@@:......#@O..... ",
                    " ..%@$@@&.>,<.X@@...... ",
                    " .$@%.*@*.1@@.$@2...... ",
                    " ;@@..$@%.3@4.#@O...... ",
                    " .........4,>.......... ",
                    " .........@@>.......... ",
                    " .........@@5.......... ",
                    " ........@@@@>......... ",
                    " ........@5>@5......... ",
                    " .......@@>.@@>........ ",
                    " .......@5...@5........ ",
                    " ......@@>...@@>....... ",
                    " ......@5.....@5>>..... ",
                    " ....@@@>.....@@@5..... ",
                    "                        "
                    ],
        'CalcD': ["24 24 5 1",
                  " 	c None", ".	c #999999", "+	c #FFFFFF", "@	c #FF0000", "#	c #07C5FB",
                  "........................",
                  ".++++++++++++++++++++++.",
                  ".++++++++++++++++++++++.",
                  ".++@@@@++++++++@+++++++.",
                  ".+@@+++@+++++++@+++++++.",
                  ".+@++++++@@@+++@+++@@@+.",
                  ".+@+++++++++@++@++@++++.",
                  ".+@++++++@@@@++@++@++++.",
                  ".+@@+++@+@++@++@++@++++.",
                  ".++@@@@++@@@@++@+++@@@+.",
                  ".++++++#+++++++++++++++.",
                  ".+++++#+#++++++++++++++.",
                  ".+++++#+#++++++++++++++.",
                  ".++++##+#++++++++++++++.",
                  ".++++#+++#+++++++++++++.",
                  ".++++#+++#+++++++++++++.",
                  ".++++#+++#+++++++++++++.",
                  ".+++##+++#+++++++++++++.",
                  ".+++#+++++#++++++++++++.",
                  ".+++#++++++#+++++++++++.",
                  ".+++#+++++++##+++++++++.",
                  ".++##+++++++++###++++++.",
                  ".++++++++++++++++++++++.",
                  "........................"
                  ],
        "XYGrid": ["24 24 4 1",
                   " 	c None", ".	c #BACDF3", "+	c #000000", "@	c #8896B2",
                   "                        ",
                   " ...................... ",
                   " ....+.....+.....+..... ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " +++++++++++++++++++++. ",
                   " .@@@+@@@@@+@@@@@+@@@@@ ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " .++++++++++++++++++++. ",
                   " ..@@+@@@@@+@@@@+@@@@@@ ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " +++++++++++++++++++++. ",
                   " .@@@+@@@@@+@@@@@+@@@@@ ",
                   " ....+@....+@....+@.... ",
                   " ....+@....+@....+@.... ",
                   " .....@.....@.....@.... ",
                   "                        "]
    }


###############################################################################
# テスト用スクリプト
###############################################################################
if __name__ == '__main__':

    pass
