message (lx_message.hpp)

From The Foundry MODO SDK wiki
Jump to: navigation, search
There are security restrictions on this page

International Messages

This module defines the interface to the International Message subsystem for internationalization (abbreviated as I18N by people in the trade). Message strings are assigned numbers and read from a database at runtime. The databases are preserved in XML within the config system. The message system looks up the right set of message strings based on the runtime language choice and the application uses that text instead of hard-coded text strings.

Table Access

Language ID's are the codes used by Windows to define the national setting. It can be read directly with a Win32 interface, but will need to be computed differently on other systems. The Windows language codes are nice because they group langauges by variants so that natural fallbacks will be close to understandable by variant subgroups. For example, UK English speakers will get US English if no UK variant messages are available. As nice as these windows-centric magic numbers may have been, they have been supplanted by an international-standards-compliant language and country code system which uses a 2 letter string (dfeined in ISO-639) to pick the language, followed by an optional ISO-3166 country code separated by an underscore.

Common Messages

The "common" message table contains a set of translatable strings that have consistent uses throughout the application. The codes are all old-style numeric, defined here.

(1) SDK: Declarations
 #define LXiCM_ACT_ERROR         100
 #define LXiCM_ACT_WARNING       101
 #define LXiCM_ACT_OK            102
 #define LXiCM_ACT_CANCEL        103
 #define LXiCM_ACT_YES           104
 #define LXiCM_ACT_NO            105
 #define LXiCM_ACT_DONE          106
 #define LXiCM_ACT_YESALL        107
 #define LXiCM_ACT_RENAME        108
 #define LXiCM_ACT_ADD           109
 #define LXiCM_ACT_DELETE        110
 #define LXiCM_ACT_CLEAR         111
 #define LXiCM_ACT_SAVE          112
 #define LXiCM_ACT_NOSAVE        113
 #define LXiCM_ACT_LOAD          114
 #define LXiCM_ACT_CLOSE         117
 #define LXiCM_ACT_CONTINUE      118
 #define LXiCM_SPC_NONE          125
 #define LXiCM_SPC_UNNAMED       126
 #define LXiCM_SPC_MIXED         127
 #define LXiCM_ACT_INFO          128
 #define LXiCM_ACT_QUIT          132
 #define LXiCM_ACT_NAME          133
 #define LXiCM_ACT_TYPE          134
 #define LXiCM_ACT_PROJ          135
 #define LXiCM_ACT_AXIS          136
 #define LXiCM_SPC_UNKNOWN       137
 #define LXiCM_ACT_COPY          138
 #define LXiCM_ACT_CUT           139
 #define LXiCM_ACT_PASTE         140
 #define LXiCM_SPC_NEW           141
 #define LXiCM_ACT_NEW           141
 #define LXiCM_ACT_VOID          142
 #define LXiCM_SPC_VOID          142
 #define LXiCM_ACT_ALL           143
 #define LXiCM_SPC_ALL           143
 #define LXiCM_ACT_EXPORT        144
 #define LXiCM_ACT_PROPS         145
 #define LXiCM_ACT_HELP          146
 #define LXiCM_ACT_FUTURE        147
 #define LXiCM_ACT_SHOWM         148
 #define LXiCM_ACT_HIDE          149
 #define LXiCM_SPC_UNTITLE       150
 #define LXiCM_ACT_REPLACE       151
 #define LXiCM_ACT_RELOAD        152
 #define LXiCM_ACT_DUPLICATE     153
 #define LXiCM_SPC_PRIVATE       169
 #define LXiCM_SPC_PLUGINS       170
 #define LXiCM_SPC_ALLFILES      171
 #define LXiCM_SPC_ALLFORMATS    172
 #define LXiCM_ACT_SAVEAS        173
 #define LXiCM_ACT_BAKE          188
 #define LXiCM_ACT_INSTANCE      195
 #define LXiCM_SPC_DEFAULT       196
 #define LXiCM_ACT_LOADIMAGE     197
 #define LXiCM_ACT_NOALL         198
 #define LXiCM_ACT_NEWIMAGE      203
 #define LXiCM_ACT_LOADSEQ       213
 #define LXiCM_ACT_NEWSEQ        214
 #define LXiCM_ACT_DEFORM        216
 #define LXiCM_ACT_CHOOSECOLOR   217
 #define LXiCM_ACT_ADDMAP        218
 #define LXiCM_ACT_MOVE          700
 #define LXiCM_ACT_PERFORMDROP   701
 #define LXiCM_ACT_CANCELDROP    703

(2) RESRC: common keys
 <hash type="T" key="99">%1</hash>
 <hash type="T" key="100">Error</hash>
 <hash type="T" key="101">Warning</hash>
 <hash type="T" key="102">OK</hash>
 <hash type="T" key="103">Cancel</hash>
 <hash type="T" key="104">Yes</hash>
 <hash type="T" key="105">No</hash>
 <hash type="T" key="106">Done</hash>
 <hash type="T" key="107">Yes to All</hash>
 <hash type="T" key="108">Rename</hash>
 <hash type="T" key="109">Add</hash>
 <hash type="T" key="110">Delete</hash>
 <hash type="T" key="111">Clear</hash>
 <hash type="T" key="112">Save</hash>
 <hash type="T" key="113">Don't Save</hash>
 <hash type="T" key="114">Load</hash>
 <hash type="T" key="115">Assign</hash>
 <hash type="T" key="116">Unassign</hash>
 <hash type="T" key="117">Close</hash>
 <hash type="T" key="118">Continue</hash>
 <hash type="T" key="129">Find</hash>
 <hash type="T" key="130">Search</hash>
 <hash type="T" key="131">New Group</hash>
 <hash type="T" key="125">(none)</hash>
 <hash type="T" key="126">(unnamed)</hash>
 <hash type="T" key="127">(mixed)</hash>
 <hash type="T" key="128">Information</hash>
 <hash type="T" key="132">Quit</hash>
 <hash type="T" key="133">Name</hash>
 <hash type="T" key="134">Type</hash>
 <hash type="T" key="135">Projection</hash>
 <hash type="T" key="136">Axis</hash>
 <hash type="T" key="137">(unknown)</hash>
 <hash type="T" key="138">Copy</hash>
 <hash type="T" key="139">Cut</hash>
 <hash type="T" key="140">Paste</hash>
 <hash type="T" key="141">(new)</hash>
 <hash type="T" key="142">(void)</hash>
 <hash type="T" key="143">(all)</hash>
 <hash type="T" key="144">Export</hash>
 <hash type="T" key="145">Properties</hash>
 <hash type="T" key="146">Help</hash>
 <hash type="T" key="147">In the future</hash>
 <hash type="T" key="148">Show message dialog</hash>
 <hash type="T" key="149">Hide message</hash>
 <hash type="T" key="150">Untitled</hash>
 <hash type="T" key="151">Replace</hash>
 <hash type="T" key="152">Reload</hash>
 <hash type="T" key="153">Duplicate</hash>
 <hash type="T" key="154">Hide all messages like this one</hash>
 <hash type="T" key="155">Always &quot;Yes&quot;</hash>
 <hash type="T" key="156">Always &quot;OK&quot;</hash>
 <hash type="T" key="157">Always &quot;Yes to All&quot;</hash>
 <hash type="T" key="158">Always &quot;No&quot;</hash>
 <hash type="T" key="159">Always &quot;Cancel&quot;</hash>
 <hash type="T" key="160">&quot;Yes&quot; to all messages like this one</hash>
 <hash type="T" key="161">&quot;OK&quot; to all messages like this one</hash>
 <hash type="T" key="162">&quot;Yes to All&quot; to all messages like this one</hash>
 <hash type="T" key="163">&quot;No&quot; to all messages like this one</hash>
 <hash type="T" key="164">&quot;Cancel&quot; to all messages like this one</hash>
 <hash type="T" key="165">Confirmation Request</hash>
 <hash type="T" key="169">(private)</hash>
 <hash type="T" key="170">Plugins</hash>
 <hash type="T" key="171">All Files</hash>
 <hash type="T" key="172">All Formats</hash>
 <hash type="T" key="173">Save As</hash>
 <hash type="T" key="174">Label</hash>
 <hash type="T" key="175">Command</hash>
 <hash type="T" key="176">Left</hash>
 <hash type="T" key="177">Right</hash>
 <hash type="T" key="178">Middle</hash>
 <hash type="T" key="179">Button 4</hash>
 <hash type="T" key="180">Button 5</hash>
 <hash type="T" key="181">Button 6</hash>
 <hash type="T" key="182">Button 7</hash>
 <hash type="T" key="183">Button 8</hash>
 <hash type="T" key="184">Button 9</hash>
 <hash type="T" key="185">Button 10</hash>
 <hash type="T" key="186">Click</hash>
 <hash type="T" key="187">Double Click</hash>
 <hash type="T" key="188">Bake</hash>
 <hash type="T" key="189">[Any Key]</hash>
 <hash type="T" key="190">[Any Button]</hash>
 <hash type="T" key="191">[Anywhere]</hash>
 <hash type="T" key="192">Key assignments applied to all regions within the input map</hash>
 <hash type="T" key="193">(multiple)</hash>
 <hash type="T" key="194">(new key)</hash>
 <hash type="T" key="195">Make Instance</hash>
 <hash type="T" key="196">(default)</hash>
 <hash type="T" key="197">(load image)</hash>
 <hash type="T" key="198">No to All</hash>
 <hash type="T" key="AlwaysNoToAll">Always &quot;No to All&quot;</hash>
 <hash type="T" key="199">&quot;No to All&quot; to all messages like this one</hash>
 <hash type="T" key="200">Click Hold</hash>
 <hash type="T" key="201">Hold</hash>
 <hash type="T" key="202">load image</hash>
 <hash type="T" key="203">(new image)</hash>
 <hash type="T" key="204">Invert X and Y</hash>
 <hash type="T" key="205">Invert X</hash>
 <hash type="T" key="206">Invert Y</hash>
 <hash type="T" key="207">Invert</hash>
 <hash type="T" key="208">Wheel Up</hash>
 <hash type="T" key="209">Wheel Down</hash>
 <hash type="T" key="210">Wheel Up and Down</hash>
 <hash type="T" key="211">[Noop]</hash>
 <hash type="T" key="212">Blocks combos from being used this input maps, and keeps them from falling through to other input maps</hash>
 <hash type="T" key="213">(load sequence)</hash>
 <hash type="T" key="214">(new sequence)</hash>
 <hash type="T" key="215">(delete)</hash>
 <hash type="T" key="216">Deform</hash>
 <hash type="T" key="217">Choose Color</hash>
 <hash type="T" key="218">(add map)</hash>
 <hash type="T" key="700">Move</hash>
 <hash type="T" key="701">Perform Drop</hash>
 <hash type="T" key="702">Create Preset</hash>
 <hash type="T" key="703">Cancel Drop</hash>
 <hash type="T" key="cineIncompatible">Operation attempted on incompatible scenes.</hash>

Message Service

MessageService provides access to message tables, which contain localized human-readable versions of internal strings used within the application. All strings presented to the user should come from messagte tables.

(3) SDK: Declarations
 #define LXu_MESSAGESERVICE      "86A69B5D-ACFA-11D9-B38C-000A956C2E10"
 #define LXa_MESSAGESERVICE      "messageservice"

As usual, the service starts with a ScriptQuery method.

(4) SDK: ILxMessageService interface
         LXxMETHOD(  LxResult,
 ScriptQuery) (
         LXtObjectID              self,
         void                   **ppvObj);

ILxMessage Management

This allocate a new ILxMessage object. This object can then be populated with a message code and message table entry.

(5) SDK: ILxMessageService interface
         LXxMETHOD(  LxResult,
 Allocate) (
         LXtObjectID              self,
         void                   **ppvObj);

(6) User Service Class: MessageService method
 NewMessage (
         CLxLoc_Message           &msg)
         LXtObjectID               obj;
         LxResult                  rc;
         rc = Allocate( &obj );
         if( LXx_FAIL( rc ) )
                 return false;
         return msg.take( obj );

An existing ILxMessage object can be duplicated with this method.

(7) SDK: ILxMessageService interface
         LXxMETHOD(  LxResult,
 Duplicate) (
         LXtObjectID              self,
         LXtObjectID              msg,
         void                   **ppvObj);

(8) User Service Class: MessageService method
 DuplicateMessage (
         CLxLoc_Message           &msg,
         CLxLoc_Message           &source)
         LxResult                  rc;
         LXtObjectID               obj;
         rc = Duplicate( source, &obj );
         if( !LXx_FAIL( rc ) )
                 return false;
         return msg.take( obj );

Reading from Message Tables

This return a human-readable string from the given message object. This fails if there is no message text, but will also set the buffer to an empty string.

(9) SDK: ILxMessageService interface
         LXxMETHOD(  LxResult,
 MessageText) (
         LXtObjectID              self,
         LXtObjectID              msg,
         char                    *buf,
         unsigned                 len);

(10) User Service Class: MessageService method
 GetText (
         CLxLoc_Message          &msg,
         char                    *buf,
         unsigned                 len)
         return MessageText( msg, buf, len );

This is a safe string "get" using a dummy class to act as callback for the safe string "read" template.

(11) User Service Class: MessageService method
 class Tmp_Sgs {
         CLxLoc_MessageService   *srv;
         ILxUnknownID             msg;
         LxResult sgs_GetString (char *buf, unsigned int len)
                 return srv->MessageText (msg, buf, len);
 GetText (
         CLxLoc_Message          &msg,
         std::string             &text)
         Tmp_Sgs                          tmp;
         CLxSafeGetString<Tmp_Sgs>        sgs;
         tmp.srv = this;
         tmp.msg = msg;
         return sgs.GetString (tmp, text);

Finally it's possible to get the raw message pattern directly from the message table, without substitution and without using an ILxMessage object. If 'table' is null, the message text will be decoded using the '@table@msg@' format.

(12) SDK: ILxMessageService interface
         LXxMETHOD(  LxResult,
 RawText) (
         LXtObjectID              self,
         const char              *table,
         const char              *msg,
         const char             **text);

Argument Types

Argument Type, in this context, refers to the user-displayed TextValueHints used as options for popup-style controls. These are stored under an ArgumentType key in the config, matching the internal name of the argument with a human-readable user name. Popups specify their argument type through some other mechanism, such as a Command's cmdhelp or an item's UI Reg data.

The config format is fairly striaght-forward, with an each ArgumentType containing a username description, and any number of Option with keys matching the internal strings representing each option, and with each Option also containing a username and description. The ArgumentType hash is a combination of the internal name and an associated language code, similar to what is done for message tables.

(13) Argument Type Example
 <atom type="CommandHelp">
   <hash type="ArgumentType" key="select-mode@en_US">
     <atom type="UserName">Selection Mode Specifier</atom>
     <atom type="Desc">Modes modify selection commands to perform different actions.</atom>
     <hash type="Option" key="set">
       <atom type="UserName">Set Primary</atom>
       <atom type="Desc">The selection becomes the primary selected element.</atom>

These methods return the username and description of a given argument type.

(14) SDK: ILxMessageService interface
         LXxMETHOD(  LxResult,
 ArgTypeUserName) (
         LXtObjectID              self,
         const char              *argType,
         char                    *buf,
         unsigned                 len);
         LXxMETHOD(  LxResult,
 ArgTypeDesc) (
         LXtObjectID              self,
         const char              *argType,
         char                    *buf,
         unsigned                 len);

These get a specific user string given an internal option name and an argument type name.

(15) SDK: ILxMessageService interface
         LXxMETHOD(  LxResult,
 ArgTypeOptionUserName) (
         LXtObjectID              self,
         const char              *argType,
         const char              *option,
         char                    *buf,
         unsigned                 len);
         LXxMETHOD(  LxResult,
 ArgTypeOptionDesc) (
         LXtObjectID              self,
         const char              *argType,
         const char              *option,
         char                    *buf,
         unsigned                 len);

Empty message service Python user class.

(16) PY: MessageService method

File Types

File types are normally determined by the presence of loaders and savers, although additional types can come from other sources. One-off file types can be defined in resources. The hash key should be the unique name for the specific file format, and is the value passed to the save dialog. The "class" is the value passed to the load dialog for building a list of, types for the same class of data object. This allows multiple format choices when loading, although this is typically not used by plug-ins.

(17) File Type Resource Sample
 <atom type="FileSystem">
   <hash type="FileType" key="lxir">
     <atom type="Class">irrad</atom>
     <atom type="Pattern">*.lxi</atom>
     <atom type="Extension">LXI</atom>

The user name for the format comes from the "filetypes" message table using the same hash key.


We often have static data that should be sorted into categories. This includes entities like tools, commands, shaders, other plug-in classes, and so on. The category system allows us to generically classify statically-named entries into a hierarchy.

Config Management

All categories are stored in the config using a format similar to message tables. The "Category" hash identifies the category itself with a key. The hash's children are all "C", with the key being the specific data to be categoried. The value is a slash-delimited path representing the position of the entry in the hierarchy. Since the se are hashes, the entry names are case-sensitive.

(18) SDK: Category Example
 <atom type="Categories">
   <hash type="Category" key="Commands">
     <hash type="C" key="select.more">ui/select</hash>

The usernames for the entries in the hiearchy are found in message tables named through the category key and the string ":category", as shown below. The message lookups are the path component itself. Remember that you need to provide usernames for each part of the path.

(19) SDK: Category Path Messages Example
 <atom type="Messages">
   <hash type="Table" key="Commands:category.en_US">
     <hash type="T" key="ui">UI</hash>
     <hash type="T" key="ui/select">Select</hash>

Auto-Save Events

Auto-saving is triggered periodically based on user preferences, modified by when the system believes an autosave is safe to perform. Other clients can get in on this by listening to the auto-save event port. There is only one event, AutoSaveNow(), at which point the client can safely perform an auto-save if applicable. This event is sent after the nexus has done its own auto-saving.

(20) SDK: Declarations
 #define LXa_AUTOSAVELISTENER    "autosavelistener"
 #define LXu_AUTOSAVELISTENER    "04f41d4e-7267-430e-81f4-a89896bf746c"

(21) SDK: ILxAutoSaveListener interface
         LXxMETHOD(  LxResult,
 AutoSaveNow) (
         LXtObjectID              self);

Empty AutoSaveListener Python user class.

(22) PY: AutoSaveListener method