サンプル コード

closestPointOnCurve プラグインからとった以下のサンプル コードは、ローカライズしたユーザ インタフェース文字列をサポートするためにどのようにコードが修正されているかを示します。関連する変更は斜体で示します。このプラグインのソース コードのセット全体は、Maya Bonus Tool の一部として提供されています。

closestPointOnCurvePlugin.cpp

プラグインを初期化すると、MFnPlugin::registerUIStrings() がコールされて C++ コードが使用する文字列が登録され、MEL 文字列リソースを登録してローカライズ値をロードする MEL コマンド closestPointOnCurveInitStrings がコールされます。closestPointOnCurveStrings.h ヘッダ ファイルは、プラグインが使用する C++ 文字列リソースの単一定義点を提供するために作成されました。

// File: closestPointOnCurveStrings.cpp
// HEADER FILES:
#include "closestPointOnCurveCmd.h"
#include "closestPointOnCurveNode.h"
#include "closestPointOnCurveStrings.h"
#include <maya/MFnPlugin.h>

// Register all strings used by the plugin C++ source 
static MStatus registerMStringResources(void)
{
      
    MStringResource::registerString(kNoValidObject);
    MStringResource::registerString(kInvalidType);
    MStringResource::registerString(kNoQueryFlag);
    return MS::kSuccess;
}

// INITIALIZES THE PLUGIN BY REGISTERING COMMAND AND NODE:
MStatus initializePlugin(MObject obj)
{
    MStatus status;
    MFnPlugin plugin(obj, PLUGIN_COMPANY, "4.0", "Any");

    // Register string resources used in the code and scripts
    // This is done first, so the strings are available.
    status = plugin.registerUIStrings(registerMStringResources, "closestPointOnCurveInitStrings");
    if (!status)
    {
        status.perror("registerUIStrings");
        return status;
    }
    status = plugin.registerCommand("closestPointOnCurve",  closestPointOnCurveCommand::creator,  closestPointOnCurveCommand::newSyntax);
    if (!status)
    {
        status.perror("registerCommand");
        return status; 
    }
    status = plugin.registerNode("closestPointOnCurve",  closestPointOnCurveNode::id, closestPointOnCurveNode::creator,  closestPointOnCurveNode::initialize);
    if (!status)
    {
        status.perror("registerNode");
        return status;
    }
    return status;
}

closestPointOnCurveStrings.h

このヘッダ ファイルは、プラグインの C++ モジュールで使用する文字列リソースを定義するために追加されました。複数のソース ファイルでリソースにアクセスする場合は、MStringResourceId 値の共通定義セットを提供するために、このようなヘッダ ファイルの使用をお勧めします。

// File: closestPointOnCurveStrings.h
// MAYA HEADER FILES:
#include <maya/MStringResource.h>
#include <maya/MStringResourceId.h>
// MStringResourceIds contain plugin id, unique resource id for
// each string and the default value for the string.
#define kPluginId  "closestPointOnCurve"
#define kNoValidObject MStringResourceId(kPluginId,"kNoValidObject", \ "A curve or its transform node must be specified as a command argument, or using your current selection.")
#define kInValidType MSTringResourceId (kPluginID, "kInvalidType", \ "Object ^1s has invalid type. Only a curve or its transform can be specified.")
#define kNoQueryFlag MStringResourceId (kPluginId, "kNoQueryFlag", \ "You must specify AT LEAST ONE queryable flag in query mode. Use the "help" command to list all available flags.")

closestPointOnCurveCmd.cpp

このファイルは、以前は、ハードコードされた文字列を使用してエラー メッセージを表示していました。ハードコードされた文字列が MStringResourceId オブジェクトとして closestPointOnCurveStrings.h で再定義されました。文字列リソースを使用するには、MStringResource::getString() をコールしてリソースの現在値を取得します。このコードは、変数引数をメッセージ文字列に挿入する MString::format() メソッドの使用も例示しています。国際化コードでは、文字列の連結ではなく、フォーマットを使用してメッセージ文字列を構築することをお勧めします。フォーマットした文字列を使用すると、文字列を別の言語に翻訳するときに、位置の引数を正しい文脈と位置に正しく配置できます。

// FILE: closestPointOnCurveCmd.cpp
// HEADER FILES:
#include "closestPointOnCurveCmd.h"
#include "closestTangentUAndDistance.h"
#include "closestPointOnCurveStrings.h"
// COMPUTING THE OUTPUT VALUES FOR THE CLOSEST POSITION, NORMAL, TANGENT,  
// PARAMETER-U AND DISTANCE, OR CREATING A "closestPointOnCurve" NODE:
MStatus closestPointOnCurveCommand::redoIt()
{
    // DOUBLE-CHECK TO MAKE SURE THERE'S A SPECIFIED OBJECT TO EVALUATE ON:
    if (sList.length() == 0)
    {
        MStatus stat;
        MString msg = MStringResource::getString(kNoValidObject, stat);          
        displayError(msg);
        return MStatus::kFailure;
    }

    // RETRIEVE THE SPECIFIED OBJECT AS A DAGPATH:
    MDagPath curveDagPath;
    sList.getDagPath(0, curveDagPath);

    // CHECK FOR INVALID NODE-TYPE INPUT WHEN SPECIFIED/SELECTED 
    // NODE IS *NOT* A "CURVE" NOR "CURVE TRANSFORM":
    if (!curveDagPath.node().hasFn(MFn::kNurbsCurve) && 
        !(curveDagPath.node().hasFn(MFn::kTransform) 
        && curveDagPath.hasFn(MFn::kNurbsCurve)))
    {
        MStatus stat;
        MString msg; 
        // Use format to place variable string into message
        MString msgFmt = MStringResource::getString(kInvalidType, stat);
        MStringArray selectionStrings;
        sList.getSelectionStrings(0, selectionStrings);
        msg.format(msgFmt, selectionStrings[0]);
        displayError(msg);
        return MStatus::kFailure;
    }

    // WHEN COMMAND *NOT* IN "QUERY MODE" (I.E. "CREATION MODE"), CREATE AND 
    // CONNECT A "closestPointOnCurve" NODE AND RETURN ITS NODE NAME:
    if (!queryFlagSet)
    {
        // CREATE THE NODE:
        MFnDependencyNode depNodeFn;
        if (closestPointOnCurveNodeName == "")
            depNodeFn.create("closestPointOnCurve");
        else
            depNodeFn.create("closestPointOnCurve", closestPointOnCurveNodeName);
        closestPointOnCurveNodeName = depNodeFn.name();

        // SET THE ".inPosition" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
        if (inPositionFlagSet)
        {
            MPlug inPositionXPlug = depNodeFn.findPlug("inPositionX");
            inPositionXPlug.setValue(inPosition.x);
            MPlug inPositionYPlug = depNodeFn.findPlug("inPositionY");
            inPositionYPlug.setValue(inPosition.y);
            MPlug inPositionZPlug = depNodeFn.findPlug("inPositionZ");
            inPositionZPlug.setValue(inPosition.z);
        }

        // MAKE SOME ADJUSTMENTS WHEN THE SPECIFIED NODE IS A 
        // "TRANSFORM" OF A CURVE SHAPE:
        unsigned instanceNumber=0;
        if (curveDagPath.node().hasFn(MFn::kTransform))
        {
            // EXTEND THE DAGPATH TO ITS CURVE "SHAPE" NODE:
            curveDagPath.extendToShape();

            // TRANSFORMS ARE *NOT* NECESSARILY THE "FIRST" INSTANCE 
            // TRANSFORM OF A CURVE SHAPE:
            instanceNumber = curveDagPath.instanceNumber();
        }

       // CONNECT THE NODES:
       MPlug worldCurvePlug, inCurvePlug;
       inCurvePlug = depNodeFn.findPlug("inCurve");
       depNodeFn.setObject(curveDagPath.node());
       worldCurvePlug = depNodeFn.findPlug("worldSpace");
       worldCurvePlug =    worldCurvePlug.elementByLogicalIndex(instanceNumber);
       MDGModifier dgModifier;
       dgModifier.connect(worldCurvePlug, inCurvePlug);
       dgModifier.doIt();

       // SET COMMAND RESULT TO BE NEW NODE'S NAME, AND RETURN:
       setResult(closestPointOnCurveNodeName);
       return MStatus::kSuccess;
    }

    // OTHERWISE, WE'RE IN THE COMMAND'S "QUERY MODE":
    else
    {

        // COMPUTE THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U 
        // AND DISTANCE, USING THE *FIRST* INSTANCE TRANSFORM WHEN CURVE 
        // IS SPECIFIED AS A "SHAPE":
        MPoint position;
        MVector normal, tangent;
        double paramU, distance;
        closestTangentUAndDistance(curveDagPath, inPosition, position, normal, tangent, paramU, distance);
        // WHEN NO QUERYABLE FLAG IS SPECIFIED, INDICATE AN ERROR:
        if (!positionFlagSet && !normalFlagSet && !tangentFlagSet && !paramUFlagSet && !distanceFlagSet)
        {
            MStatus stat;
            MString msg = MStringResource::getString(kNoQueryFlag, stat);
            displayError(msg);
            return MStatus::kFailure;
        }

        // WHEN JUST THE "DISTANCE" IS QUERIED, RETURN A SINGLE 
        // "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE COMMAND:
        else if (distanceFlagSet && !(positionFlagSet || normalFlagSet ||       tangentFlagSet || paramUFlagSet))
        setResult(distance);
        // WHEN JUST THE "PARAMETER-U" IS QUERIED, RETURN A 
        // SINGLE "FLOAT" INSTEAD OF AN ENTIRE FLOAT ARRAY FROM THE      COMMAND:
        else if (paramUFlagSet && !(positionFlagSet || normalFlagSet || tangentFlagSet || distanceFlagSet))
        setResult(paramU);

        // OTHERWISE, SET THE RETURN VALUE OF THE COMMAND'S RESULT TO 
        // A "COMPOSITE ARRAY OF FLOATS":
        else
        {
            // HOLDS FLOAT ARRAY RESULT:
            MDoubleArray floatArrayResult;
            // APPEND THE RESULTS OF THE CLOSEST POSITION, NORMAL, 
            // TANGENT, PARAMETER-U AND DISTANCE VALUES TO THE FLOAT ARRAY RESULT:
            if (positionFlagSet)
            {
                floatArrayResult.append(position.x);
                floatArrayResult.append(position.y);
                floatArrayResult.append(position.z);
            }
            if (normalFlagSet)
            {
                floatArrayResult.append(normal.x);
                floatArrayResult.append(normal.y);
                floatArrayResult.append(normal.z);
            }
            if (tangentFlagSet)
            {
                floatArrayResult.append(tangent.x);
                floatArrayResult.append(tangent.y);
                floatArrayResult.append(tangent.z);
            }
            if (paramUFlagSet)
                floatArrayResult.append(paramU);
            if (distanceFlagSet)
                floatArrayResult.append(distance);

            // FINALLY, SET THE COMMAND'S RESULT:
            setResult(floatArrayResult);
        }
        return MStatus::kSuccess;
    }
}

closestPointOnCurveCmdInitStrings.mel

このファイルは MFnPlugin::registerStringResources のコールで参照される文字列の初期化スクリプトです。このファイルには、以下の 2 つの目的があります。

  1. このファイルは、プラグイン MEL スクリプトで使用されるすべての文字列リソースを登録します。この例で登録する文字列は、AEclosestPointOnCurveTemplate.mel で使用します。
  2. このファイルは、このプラグインのローカライズされた文字列値を含むファイルの名前で loadPluginLanguageResources をコールします。この例では、loadPluginLanguageResources によって期待される言語固有の適切な場所にある場合、closestPointOnCurve.pres.mel がロードされます。

// FILE: closestPointOnCurveInitStrings.mel
// DESCRIPTION: Register script resources and load localized 
// resources for the "closestPointOnCurve" plugin
global proc closestPointOnCurveInitStrings()
{
    // Register script resources
    registerPluginResource("closestPointOnCurve", "kAETitle", "Closest Point On Curve Attributes");
    registerPluginResource("closestPointOnCurve", "kInputCurve", "Input Curve");
    registerPluginResource("closestPointOnCurve", "kResults", "Results");
    // Load any localized resources 
    loadPluginLanguageResources("closestPointOnCurve", "closestPointOnCurve.pres.mel");

}

AEclosestPointOnCurveTemplate.mel

このファイルは、このプラグインが作成する closestPointOnCurve ノードのカスタム アトリビュート エディタ セットアップを定義します。このコードは、アトリビュート エディタのラベルのハード コード文字列ではなく、文字列リソースを使用するよう修正されました。アトリビュート名自体も翻訳形式で表示できますが、プログラマがアトリビュートごとに文字列リソースを指定する必要はありません。プラグインが定義するすべてのアトリビュートには、抽出したリソース ファイルを自動的に生成する attributeNiceName リソースが含まれます。

// FILE: AEclosestPointOnCurveTemplate.mel
global proc AEclosestPointOnCurveTemplate(string $nodeName)
{
    string $titleStr = getPluginResource("closestPointOnCurve", "kAETitle");
    string $inputCurveLabel = getPluginResource("closestPointOnCurve", "kInputCurve");
    string $resultLabel = getPluginResource("closestPointOnCurve", "kResults");
    editorTemplate -beginScrollLayout;
    editorTemplate -beginLayout $titleStr -collapse 0;
    editorTemplate -callCustom ( "AEinputNew \""+  $inputCurveLabel +"\"" ) ( "AEinputReplace \"" + 
                    $inputCurveLabel + "\"" ) "inCurve";
    editorTemplate -addControl "inPosition";
    editorTemplate -beginLayout $resultLabel;
    editorTemplate -addControl "position";
    editorTemplate -addControl "normal";
    editorTemplate -addControl "tangent";
    editorTemplate -addControl "paramU";
    editorTemplate -addControl "distance";
    editorTemplate -endLayout;
    editorTemplate -endLayout;
    editorTemplate -suppress "inCurve";
    AEabstractBaseCreateTemplate $nodeName;
    editorTemplate -addExtraControls;
    editorTemplate -endScrollLayout;
}

closestPointOnCurve.pres.mel

このファイルには、closestPointOnCurve プラグインの抽出文字列リソースが含まれます。これは、ユーティリティ スクリプト pluginResourceUtil を使用して生成しました。C++ コードと MEL スクリプトからのすべての登録文字列は、既定値と共にファイルに抽出されます。また、プラグインが登録するノードごとに、ユーティリティが自動的に生成するノードとアトリビュートのナイス ネームも含まれます(これらのノード リソースとアトリビュート リソースには、手動登録は必要ありません)。重要なのは、英語で実行する場合、プラグインは、既定値を含むこのオリジナルの抽出ファイルを必要としないということです。すべての文字列リソースは、プラグイン自体に直接組み込まれている既定値を持っています。抽出ファイルは、他の言語に翻訳するリソースのマスタ リストとして使用します。翻訳バージョンが使用可能な場合、ファイルは、MAYA_PLUG_IN_RESOURCE_PATH に沿った言語固有の適切なリソース サブディレクトリ内にあります。

// File closestPointOnCurve.pres.mel
// Resources for Plug-in: closestPointOnCurve
// 
// ----------------------------
// Registered string resources:
// ----------------------------
setPluginResource( "closestPointOnCurve", "kAETitle", "Closest Point On Curve Attributes");
setPluginResource( "closestPointOnCurve", "kInputCurve", "Input Curve");
setPluginResource( "closestPointOnCurve", "kInvalidType", "Object ^1s has invalid type.  Only a curve or its transform can be specified.");
setPluginResource( "closestPointOnCurve", "kNoQueryFlag", "You must specify AT LEAST ONE queryable flag in query mode.  Use the `help` command to list all available flags.");
setPluginResource( "closestPointOnCurve", "kNoValidObject", "A curve or its transform node must be specified as a command argument, or using your current selection.");
setPluginResource( "closestPointOnCurve", "kResults", "Results");

// 
// --------------------------
// Registered node resources:
// --------------------------
// 
// Node: closestPointOnCurve
// 
setNodeNiceNameResource( "closestPointOnCurve", "Closest Point On Curve" );
setAttrNiceNameResource( "closestPointOnCurve", "ic", "In Curve" );
setAttrNiceNameResource( "closestPointOnCurve", "ip", "In Position" );
setAttrNiceNameResource( "closestPointOnCurve", "ipx", "In Position X" );
setAttrNiceNameResource( "closestPointOnCurve", "ipy", "In Position Y" );
setAttrNiceNameResource( "closestPointOnCurve", "ipz", "In Position Z" );
setAttrNiceNameResource( "closestPointOnCurve", "p", "Position" );
setAttrNiceNameResource( "closestPointOnCurve", "px", "Position X" );
setAttrNiceNameResource( "closestPointOnCurve", "py", "Position Y" );
setAttrNiceNameResource( "closestPointOnCurve", "pz", "Position Z" );
setAttrNiceNameResource( "closestPointOnCurve", "n", "Normal" );
setAttrNiceNameResource( "closestPointOnCurve", "nx", "Normal X" );
setAttrNiceNameResource( "closestPointOnCurve", "ny", "Normal Y" );
setAttrNiceNameResource( "closestPointOnCurve", "nz", "Normal Z" );
setAttrNiceNameResource( "closestPointOnCurve", "t", "Tangent" );
setAttrNiceNameResource( "closestPointOnCurve", "tx", "Tangent X" );
setAttrNiceNameResource( "closestPointOnCurve", "ty", "Tangent Y" );
setAttrNiceNameResource( "closestPointOnCurve", "tz", "Tangent Z" );
setAttrNiceNameResource( "closestPointOnCurve", "u", "Param U" );
setAttrNiceNameResource( "closestPointOnCurve", "d", "Distance" );