Class DIY

  • All Implemented Interfaces:
    GameComponent, PortraitProvider, Handler, java.io.Serializable, java.lang.Cloneable

    public class DIY
    extends AbstractGameComponent
    implements Handler
    A scriptable GameComponent. A DIY component delegates key functionality to an object that implements the Handler interface. This object is typically derived from script code, and so terms like "script" and "script function" will be used throughout this document to refer to the parts of the component that are implemented by the Handler proxy, but it should be understood that compiled code can also subclass DIY and provide its own Handler instance. Restricted Properties: Several properties of DIY components are restricted. Attempts to change a restricted property except from your script's create or onRead functions will cause an IllegalStateException to be thrown. Restricted properties control the component's basic structure and features, such as the number of faces it consists of. These properties cannot be changed dynamically: they are normally set within the component's create script function and never changed again. To allow cards to evolve over time, they can also be changed within the script's onRead function. So for example, a component that starts with no portrait could later add one by checking for the previous version in the onRead function (see setVersion(int)), and if found, defining a portrait key (see setPortraitKey(java.lang.String)).
    Author:
    Chris Jennings
    See Also:
    Serialized Form
    • Constructor Detail

      • DIY

        protected DIY​(Handler handler,
                      java.lang.String gameCode)
        Creates a new DIY component that will call into the given handler. If the game code represents a registered game, the new component's settings will inherit from the settings for that game.
        Parameters:
        handler - the handler instance that will be called by this component to perform customizable functions
        gameCode - the code for a game to associate with this component
        Throws:
        java.lang.NullPointerException - if the handler is null
      • DIY

        public DIY​(java.lang.String handlerScript,
                   java.lang.String gameCode,
                   boolean debug)
            throws java.io.IOException
        Creates a new DIY component that will call into the given handler. If the game code represents a registered game, the new component's settings will inherit from the settings for that game. If the debug flag is set to true, then a breakpoint will be set at the start of handler script.
        Parameters:
        handlerScript - the location of the script resource that defines the handler functions that will be called by this component to perform customizable functions
        gameCode - the code for a game to associate with this component, or null
        debug - if true, then a breakpoint is set just before executing the handler script; initialization of the handler can be stepped through from the script debugger
        Throws:
        java.io.IOException - if an exception occurs while loading the script or starting the handler
        java.lang.NullPointerException - if the handler script is null
    • Method Detail

      • createTestInstance

        public static DIY createTestInstance​(Handler h,
                                             java.lang.String gameCode)
        This helper method can be called to create a new component for testing purposes using just a Handler implementation. (This method is called by the testDIYScript() function in the diy script library.) Note that if you save a test instance, the saved file will not open correctly since the component will not know what script file to load to recreate the handler.
        Parameters:
        h - the handler instance to test
        gameCode - a game to associate with the component, or null
        Returns:
        a new DIY instance that will call into the provided handler
      • getClassName

        public java.lang.String getClassName()
        Description copied from interface: GameComponent
        Returns the standard class map name that describes this component. For a compiled component this is the fully qualified name of the class. For a standard DIY component, it is diy: followed by the resource path of the script file. If the component was created from a script: class map entry, that will not be returned. The name of the true underlying type that was ultimately created by the script is returned instead.
        Specified by:
        getClassName in interface GameComponent
        Returns:
        the class map type of this instance
      • getHandlerScript

        public java.lang.String getHandlerScript()
        Returns the resource name used to create a Handler for this component, or null if the component was created directly from a Handler instance. Typically the resource used to create a handler is a script file, but it can also be the name of a class on the class path that implements the Handler interface.
        Returns:
        the resource used to create this component, or null
      • getExtensionName

        public java.lang.String getExtensionName()
        Returns an extension name that can be reported to the user as the plug-in required for this component to load correctly.
        Returns:
        the extension plug-in that adds this component type to the class map
      • setExtensionName

        public void setExtensionName​(java.lang.String extensionName)
        Sets the name of an extension to report to the user if the script required by this component cannot be found.

        This is a restricted property.

        Parameters:
        extensionName - extension required to instantiate this component
      • getVersion

        public int getVersion()
        Returns the version number of this component. The version number is stored in the component's save file and can be used to transparently upgrade components saved from older versions of the component's handler script.
        Returns:
        the version number of the component
        See Also:
        setVersion(int)
      • setVersion

        public void setVersion​(int version)
        Sets the version number of this component. The version number should be when the component is created. When a new, incompatible version of the script is released, the next higher version number can be set. Then, in the component's Handler.onRead(ca.cgjennings.apps.arkham.diy.DIY, java.io.ObjectInputStream) function, check for older versions and upgrade the component as necessary (for example, assign default values to any new settings used by the component).

        Note: The version numbers are integers; although you can assign a value like 1.1 from a script file, all decimal digits will be dropped.

        This is a restricted property.

        Parameters:
        version - the version number you have assigned to this component
        See Also:
        getVersion()
      • getCardVersion

        @Deprecated
        public final int getCardVersion()
        Deprecated.
        Replaced by getVersion().
      • setCardVersion

        @Deprecated
        public final void setCardVersion​(int version)
        Deprecated.
        Replaced by setVersion(int).
      • getFaceStyle

        public DIY.FaceStyle getFaceStyle()
        Returns the DIY.FaceStyle used by this card.
        Returns:
        the value that determines the number and type of card faces presented by this component
      • setFaceStyle

        public void setFaceStyle​(DIY.FaceStyle faceStyle)
        Sets the DIY.FaceStyle used by this card. The face style controls the number and style of the faces presented by this component.

        This is a restricted property.

        Parameters:
        faceStyle - the value that determines the number and type of card faces used by this component
        Throws:
        java.lang.NullPointerException - if the style is null
      • getFrontTemplateKey

        public java.lang.String getFrontTemplateKey()
        Returns the template key for the front face of this component. This is equivalent to getTemplateKey( 0 ).
        Returns:
        the front face template key
        See Also:
        setTemplateKey(int, java.lang.String)
      • setFrontTemplateKey

        public void setFrontTemplateKey​(java.lang.String frontTemplateKey)
        Sets the template key for the front face of this component. This is equivalent to setTemplate( 0, frontTemplateKey ).

        This is a restricted property.

        Parameters:
        frontTemplateKey - the template key to use for the front face
        Throws:
        java.lang.NullPointerException - if the key is null
        See Also:
        setTemplateKey(int, java.lang.String)
      • getBackTemplateKey

        public java.lang.String getBackTemplateKey()
        Returns the template key for the back face of this component. This is equivalent to getTemplateKey( 1 ).
        Returns:
        the back face template key
        See Also:
        setTemplateKey(int, java.lang.String)
      • setBackTemplateKey

        public void setBackTemplateKey​(java.lang.String backTemplateKey)
        Sets the template key for the back face of this component. This is equivalent to setTemplate( 1, backTemplateKey ).

        This is a restricted property.

        Parameters:
        backTemplateKey - the base template key name to use for the back face
        Throws:
        java.lang.NullPointerException - if the key is null
        See Also:
        setTemplateKey(int, java.lang.String)
      • getTemplateKey

        public java.lang.String getTemplateKey​(int index)
        Returns the base template key name for the face with the given index.
        Parameters:
        index - the index of the face to obtain a key for (0 for the first front face, 1 for the first back face, 2 for the second front face, and so on)
        Returns:
        the base template key for specified face
        Throws:
        java.lang.IndexOutOfBoundsException - if the face index is invalid for the face style
      • setTemplateKey

        public void setTemplateKey​(int index,
                                   java.lang.String templateKey)
        Sets the template key for the face with the given index. The template key is the base name for a collection of setting keys that define the properties of the template for that face, including its size and background image. The following setting keys are derived from the base key name:
        templateKey-template
        the resource file that contains the image
        templateKey-ppi
        if defined, the resolution of the template image in pixels per inch (2.54cm) (default is 150); the suffix -dpi can also be used
        templateKey-expsym-region
        if defined, the region where the expansion symbol is drawn (default is no expansion symbol)
        templateKey-expsym-invert
        if defined, the default index of the variant style to use for the expansion symbol (default is 0)
        templateKey-upsample
        the upsample factor for previews (default is 1.0); this is a multiplier for the card resolution to be used when previewing the component; it is sometimes useful for small templates that use small text (6 points or so)

        This is a restricted property.

        Parameters:
        index - the index of the face to set the template for (0 for the first front face, 1 for the first back face, 2 for the second front face, and so on)
        templateKey - the base template key name for the face
        Throws:
        java.lang.NullPointerException - if the key is null
        java.lang.IndexOutOfBoundsException - if the index is not valid for the face style
        See Also:
        getTemplateKey(int), setFaceStyle(ca.cgjennings.apps.arkham.diy.DIY.FaceStyle)
      • setSheetTitle

        public void setSheetTitle​(int index,
                                  java.lang.String title)
        Sets a custom title for the sheet with the specified index. Sheet titles are used to describe the purpose of each sheet in the user interface. Typical sheet titles include "Front Face", "Back Face", and "Marker" (localized for the interface language). If you do not set any custom titles, then the titles for this component's sheets will be generated automatically based on the FaceStyle.

        If the title that you set begins with an '@' character, then the sheet's true title will be looked up using the active user interface language whenever the titles are requested. This allows you to set a custom sheet title once (during onCreate) and yet get a correctly localized title when the resulting component is saved and later reopened using a different language setting.

        This is a restricted property.

        Parameters:
        index - the index of the sheet whose title should be modified
        title - the new title to set
        Throws:
        java.lang.NullPointerException - if the title is null
        java.lang.IllegalArgumentException - if the index is not valid for the FaceStyle
        See Also:
        getSheetTitles()
      • getSheetTitles

        public java.lang.String[] getSheetTitles()
        Returns a copy of the human-readable names of the sheets used by this component. A typical result would be something like ["Front Face", "Back Face"], localized for the user interface language. Note that, since this returns a copy of the current titles, changing the values of the returned array will have no effect on the titles used by this component. To change a sheet title, you must instead call setSheetTitle(int, java.lang.String).

        If no custom sheet titles have ever been set on this component, then this will return an array of default titles based on the face style.

        Specified by:
        getSheetTitles in interface GameComponent
        Overrides:
        getSheetTitles in class AbstractGameComponent
        Returns:
        an array of sheet titles matching the assigned sheets, or null if there are no sheets attached
        See Also:
        createDefaultSheets()
      • getBleedMargin

        public double getBleedMargin()
        Returns the bleed margin for this component, in points.
        Returns:
        the component's bleed margin, in points
      • setBleedMargin

        public void setBleedMargin​(double marginInPoints)
        Sets the size of the bleed margin for this component, in points. This can be set if the component's template images include a bleed margin as part of their design so that Strange Eons will take this into account when rendering sheets with bleed margins enabled. This will affect all of the component's faces (sheets). (The default is 0, meaning there is no bleed margin included in the design.)

        If no bleed margin is set using this method, each sheet will use a bleed margin set by the setting key templateKey-bleed-margin, or 0 if the key is not set.

        This is a restricted property.

        Parameters:
        marginInPoints - the new bleed margin; this is used to adjust the location of the component's crop marks in the deck editor
        Throws:
        java.lang.IllegalArgumentException - if the margin is negative
        See Also:
        getBleedMargin()
      • getCornerRadius

        public double getCornerRadius()
        Returns the corner radius for this component, in points.
        Returns:
        the component's corner radius, in points
      • setCornerRadius

        public void setCornerRadius​(double radiusInPoints)
        Sets the radius for rounding the corners of this component, in points. This will affect all of the component's faces (sheets). (The default is 0, leaving the corners sharp.)

        If no corner radius is set using this method, each sheet will use a separate radius set by the setting key templateKey-corner-radius, or 0 if the key is not set.

        This is a restricted property.

        Parameters:
        radiusInPoints - the new corner radius; this is used to round the corners of the component when trimming the edges.
        Throws:
        java.lang.IllegalArgumentException - if the radius is negative
        See Also:
        getCornerRadius()
      • setHighResolutionSubstitutionMode

        public void setHighResolutionSubstitutionMode​(DIY.HighResolutionMode mode)
        Sets the high resolution image substitution mode used by the component. When substitution is active, certain image drawing methods defined on DIYSheet will automatically replace a standard resolution image with a resolution version. This setting is normally only changed using this method for testing purposes.
        Parameters:
        mode - the high resolution image substitution mode for this component
        Throws:
        java.lang.NullPointerException - if the mode is null
        See Also:
        getHighResolutionSubstitutionMode(), DIY.HighResolutionMode
      • getCustomFoldMarks

        public final double[] getCustomFoldMarks​(int faceIndex)
        Returns a copy of the custom fold mark array for the specified component face, or null if the face has no custom fold marks.
        Parameters:
        faceIndex - the index of the face of interest
        Returns:
        the custom fold marks set on the face, or null
        Throws:
        java.lang.IndexOutOfBoundsException - if the face index is invalid for the face style
      • setCustomFoldMarks

        public final void setCustomFoldMarks​(int faceIndex,
                                             double[] foldMarkTuples)
        Sets an array of custom fold marks to be used by this component. For more information on custom fold marks, see Sheet.getFoldMarks().

        This is a restricted property.

        Parameters:
        faceIndex - the index of the face that the fold marks will appear on
        foldMarkTuples - the fold mark unit vectors to set
        Throws:
        java.lang.IllegalArgumentException - if the length of the fold mark array is not a multiple of 4 or the vectors it defines do not have unit length
        java.lang.IndexOutOfBoundsException - if the face index is invalid for the face style
      • getTransparentFaces

        public final boolean getTransparentFaces()
        Returns true if the component's sheet uses translucent pixels.
        Returns:
        true if the component's sheets include an alpha channel
        See Also:
        setTransparentFaces(boolean)
      • setTransparentFaces

        public final void setTransparentFaces​(boolean transparent)
        This flag must be set if the card faces require support for translucent pixels; for example, if the faces have a nonrectangular shape.

        This is a restricted property.

        Parameters:
        transparent - true if the component's sheets require an alpha channel
        See Also:
        getTransparentFaces()
      • getVariableSizedFaces

        public final boolean getVariableSizedFaces()
        Returns true if the card faces can change in size.
        Returns:
        true if variable-sized faces are enabled
        See Also:
        setVariableSizedFaces(boolean)
      • setVariableSizedFaces

        public final void setVariableSizedFaces​(boolean variable)
        Sets whether faces can change in size. If true, then transparent faces will also automatically be enabled. When this option is enabled, sheets have their edges trimmed of transparent pixels before being returned. The easiest way to implement variably-sized faces is to use a template image that matches the largest possible size that is desired; if no maximum size is known ahead of time, you must replace the template image with an appropriately sized template at the start of each rendering pass.

        This is a restricted property.

        Parameters:
        variable - if true, faces may vary in size
        See Also:
        getVariableSizedFaces()
      • setDeckSnappingHint

        public void setDeckSnappingHint​(Sheet.DeckSnappingHint deckSnappingHint)
        Sets the default deck snapping behaviour when the component is placed in a deck editor.

        This is a restricted property.

        Parameters:
        deckSnappingHint - a hint describing the default snapping behaviour
        Throws:
        java.lang.NullPointerException - if the hint is null
        See Also:
        getDeckSnappingHint()
      • getPortraitKey

        public java.lang.String getPortraitKey()
        Returns the base key name that controls the default portrait handling system. Note that this key will be ignored if custom portrait handling is enabled.
        Returns:
        the portrait key base name
        See Also:
        setPortraitKey(java.lang.String), getPortrait(int)
      • setPortraitKey

        public void setPortraitKey​(java.lang.String portraitKey)
        Sets the base portrait key for this component. The base portrait key is used to compose a group of setting keys that control the built-in portrait manager. The key will be null if custom portrait handling is enabled, and trying to set the key to non-null value while custom portrait handling is enabled will result in an IllegalStateException being thrown. When custom portrait handling is disabled, setting the key to null will disable portraits for the component (getPortraitCount() will return 0). If the key is non-null, then the following keys will be referred to when setting up the portrait system:
        x-portrait-template
        the resource file that contains the default portrait image
        x-portrait-clip-region
        this is the region where the portrait will be drawn on the card
        x-portrait-scale
        if defined, sets the scale for the default portrait; otherwise the scale is determined automatically to fit the portrait in the clip region (a scale of 1 = 100%)
        x-portrait-panx
        if defined, the horizontal pan of the default portrait (default is 0)
        x-portrait-pany
        if defined, the vertical pan of the default portrait (default is 0)

        If the face style is DIY.FaceStyle.CARD_AND_MARKER, then an additional group of setting keys is used to determine the clip region, and the scale and position of the default portrait on the marker (the default portrait image will be the same).

        This is a restricted property.

        Parameters:
        portraitKey - the base portrait key, or null to disable portraits
        Throws:
        java.lang.IllegalStateException - if the key is not null and custom portrait handling is enabled
        See Also:
        setCustomPortraitHandling(boolean), getPortrait(int), setFaceStyle(ca.cgjennings.apps.arkham.diy.DIY.FaceStyle)
      • isPortraitBackgroundFilled

        public final boolean isPortraitBackgroundFilled()
        Returns true if portrait areas will be filled with solid white before painting the portrait.
        Returns:
        true if background filling is enabled
      • setPortraitBackgroundFilled

        public final void setPortraitBackgroundFilled​(boolean fill)
        If set, the portrait clip region will be filled in with solid white before painting the portrait. This is usually turned off when the user is expected to use portraits that have transparency because the portrait is painted over a background illustration.

        This is a restricted property.

        Parameters:
        fill - if true, the clip region will be filled before painting when DIYSheet.paintPortrait(java.awt.Graphics2D) is called
      • getPortraitScaleUsesMinimum

        public final boolean getPortraitScaleUsesMinimum()
        Returns true if the minimum portrait scale is used for newly installed portrait images.
        Returns:
        true if the minimum portrait scale method is used for new portrait images
        See Also:
        setPortraitScaleUsesMinimum(boolean)
      • setPortraitScaleUsesMinimum

        public final void setPortraitScaleUsesMinimum​(boolean useMinimum)
        Sets how the portrait's initial scale is determined. If false, the default, the initial scale is the smallest scale that completely covers the portrait's clip region. If true, then the initial scale will be the smallest scale that causes either the top and bottom edge of the image or the left and right edge of the image to touch the corresponding edges of the clipping region.

        This is a restricted property.

        Parameters:
        useMinimum - true to set the minimum portrait scale method for new portrait images
        See Also:
        getPortraitScaleUsesMinimum()
      • setPortraitClipping

        public final void setPortraitClipping​(boolean clipping)
        Sets whether the portrait is clipped. If true (the default), then no part of the portrait image that lies outside of the clip region will be drawn when DIYSheet.paintPortrait(java.awt.Graphics2D) is used to draw the portrait. If false, then the portrait can "escape" from the clip region and draw over any surrounding content. When set to false, the minimum scaling option is often also set.

        This is a restricted property.

        Parameters:
        clipping - true if the portrait should be clipped
        See Also:
        getPortraitClipping(), setPortraitScaleUsesMinimum(boolean)
      • setPortraitClipStencil

        public void setPortraitClipStencil​(java.awt.image.BufferedImage stencil)
        Sets an explicit clip stencil for this component's portrait. A portrait's clip stencil is used by the portrait adjustment panel to show which parts of the portrait will be occluded by other parts of the component. An explicit clip stencil overrides the default mechanism for creating a clip stencil (described below). The provided image should be the same size as the clip rectangle. The image's alpha channel should match the translucency of any graphics drawn over the portrait region. Alternatively, the stencil can be set to null to indicate that the portrait is not occluded.

        If no clip stencil is set, a default mechanism will be used to create one. This mechanism assumes that the portrait is either drawn underneath the template image for the sheet with index 0, or else not occluded. The stencil will be based on the subimage of the template image that is covered by the clipping region. If all of the pixels in this subimage are fully opaque, then the portrait is assumed to be drawn over the template and not occluded by other graphics. Otherwise, it is assumed that the template is drawn over the portrait and the subimage's alpha channel will be used to create the stencil.

        In the interest of efficiency, the portrait panel caches the clip stencil rather than requesting it repeatedly. If the clip region or stencil image change during editing, you must call the portrait panel's PortraitPanel.updatePanel() method to cause it to adjust for the stencil and clip values.

        Note: Explicit clip stencils are not saved with the component, but must be restored when the component is read from a file. A simple way to handle this is to set the clip stencil in createInterface, as this is called whether the component is new or being read from a file.

        If the component uses custom portrait handling, calling this method will throw an IllegalStateException. However, if you use DefaultPortraits in your custom handling, you can change the clip stencil using DefaultPortrait.setClipStencil(java.awt.image.BufferedImage).

        Parameters:
        stencil - an image whose alpha channel will be used by the portrait adjustment panel to clip the portrait
        Throws:
        java.lang.IllegalStateException - if custom portrait handling is used
        See Also:
        AbstractPortrait.createStencil(java.awt.image.BufferedImage, java.awt.Rectangle), isCustomPortraitHandling(), Portrait.getClipDimensions(), Portrait.getClipStencil()
      • setPortraitClipStencilRegion

        public void setPortraitClipStencilRegion​(java.awt.Rectangle region)
        Sets an explicit clip stencil region for this component's portrait. The clip stencil region is the area that the editor's portrait panel considers to be the ideal area covered by the portrait. Normally, this is the same as the portrait clip region. If a design uses transparent portraits drawn over a background, however, one might wish to set the clip stencil smaller than the true clipping region so that the default portrait scale still lets some of the background show through. In this case, you can set the this value to the true clipping region so that the portrait panel's portrait area has the correct shape.

        Note: Explicit clip stencil regions are not saved with the component, but must be restored when the component is read from a file. A simple way to handle this is to set the region in createInterface, as this is called whether the component is new or being read from a file.

        If the component uses custom portrait handling, calling this method will throw an IllegalStateException.

        Parameters:
        region - the region of the template covered by the "true" clipping region portrait adjustment panel to clip the portrait
        Throws:
        java.lang.IllegalStateException - if custom portrait handling is used
        See Also:
        isCustomPortraitHandling(), Portrait.getClipDimensions(), setPortraitClipStencil(java.awt.image.BufferedImage)
      • isMarkerBackgroundFilled

        public final boolean isMarkerBackgroundFilled()
        Returns true if marker portrait areas will be filled with solid white before painting the marker portrait.
        Returns:
        true if background filling is enabled
        Throws:
        java.lang.IllegalStateException - if the face style is not CARD_AND_MARKER
        See Also:
        setMarkerBackgroundFilled(boolean)
      • setMarkerBackgroundFilled

        public final void setMarkerBackgroundFilled​(boolean fill)
        If set, the marker portrait clip region will be filled in with solid white before painting the portrait on the marker.

        This is a restricted property.

        Parameters:
        fill - if true, the clip region will be filled before painting when DIYSheet.paintMarkerPortrait(java.awt.Graphics2D) is called
        Throws:
        java.lang.IllegalStateException - if the face style is not CARD_AND_MARKER
        See Also:
        isMarkerBackgroundFilled()
      • getMarkerScaleUsesMinimum

        public final boolean getMarkerScaleUsesMinimum()
        Returns true if the minimum portrait scale is used on the marker for newly installed portrait images.
        Returns:
        true if the minimum portrait scale method is used for new portrait images
        Throws:
        java.lang.IllegalStateException - if the face style is not CARD_AND_MARKER
        See Also:
        setMarkerScaleUsesMinimum(boolean)
      • setMarkerScaleUsesMinimum

        public final void setMarkerScaleUsesMinimum​(boolean useMinimum)
        Sets how the portrait's initial scale is determined for the marker portrait.

        This is a restricted property.

        Parameters:
        useMinimum - true to set the minimum portrait scale method for new portrait images
        Throws:
        java.lang.IllegalStateException - if the face style is not CARD_AND_MARKER
        See Also:
        getMarkerScaleUsesMinimum()
      • setMarkerClipping

        public final void setMarkerClipping​(boolean clipping)
        Sets whether the marker portrait is clipped. If true (the default), then no part of the portrait image that lies outside of the clip region will be drawn when DIYSheet.paintMarkerPortrait(java.awt.Graphics2D) is used to draw the portrait. If false, then the portrait can "escape" from the clip region and draw over any surrounding content.

        This is a restricted property.

        Parameters:
        clipping - true if the marker portrait should be clipped
        Throws:
        java.lang.IllegalStateException - if the face style is not CARD_AND_MARKER
        See Also:
        getMarkerClipping(), setMarkerScaleUsesMinimum(boolean)
      • setMarkerClipStencil

        public void setMarkerClipStencil​(java.awt.image.BufferedImage stencil)
        Sets an explicit clip stencil for the marker of a DIY.FaceStyle.CARD_AND_MARKER component. This is essentially the same as setting a portrait clip stencil except that it applies to the portrait on the marker rather than the main portrait. Refer to that method for a detailed explanation of how the clip stencil works. The only major difference is that when the default mechanism for creating a stencil is used, this will use the template image for the sheet with index 2 rather than the sheet with index 0.
        Parameters:
        stencil - an image whose alpha channel will be used by the portrait adjustment panel to clip the marker portrait
        Throws:
        java.lang.IllegalStateException - if teh face style is not CARD_AND_MAKRER or custom portrait handling is used
        See Also:
        setPortraitClipStencil(java.awt.image.BufferedImage)
      • getMarkerStyle

        public MarkerStyle getMarkerStyle()
        Returns the marker style for the marker sheet of a DIY.FaceStyle.CARD_AND_MARKER component. This style determines how a back face for the marker is generated.
        Returns:
        the component's marker style
      • isCustomPortraitHandling

        public final boolean isCustomPortraitHandling()
        Returns true if this component is providing its own Portraits through script code.

        Note: The somewhat awkward name is to allow scripts to access this value using the automatically generated getter customPortraitHandling.

        Returns:
        true if the DIY script implements the PortraitProvider interface
        See Also:
        setCustomPortraitHandling(boolean), PortraitProvider
      • setCustomPortraitHandling

        public final void setCustomPortraitHandling​(boolean scripted)
        Sets whether this component's script will provide its own portrait handling code or whether the built-in portrait management system will be used. The default is false (use the built-in system), which is suitable in most cases. If set to true, the component script must define functions to implement the PortraitProvider interface, and the component will delegate to these functions when its own getPortraitCount() and getPortrait(int) methods are called.

        This is a restricted property.

        Parameters:
        scripted - whether portrait handling will be provided by the component's built-in portrait management (false) or by script code (true)
        See Also:
        isCustomPortraitHandling(), PortraitProvider, DefaultPortrait
      • getPortrait

        public Portrait getPortrait​(int index)
        Returns the specified Portrait. If custom portrait handling is enabled, then this calls the script's getPortrait function to retrieve the portrait to return. Otherwise it will return a built-in portrait implementation: if no portrait key is set, then no portraits are available. Otherwise, the built-in portrait can be fetched using an index of 0. If the face style is DIY.FaceStyle.CARD_AND_MARKER, then the marker portrait can be fetched using an index of 1. Note that the marker portrait uses the same image as the main portrait, but has its own scale and pan values.
        Specified by:
        getPortrait in interface Handler
        Specified by:
        getPortrait in interface PortraitProvider
        Parameters:
        index - the index of the desired portrait, from 0 to getPortraitCount()-1.
        Returns:
        the requested portrait instance
        Throws:
        java.lang.IndexOutOfBoundsException - if the portrait index is invalid
        See Also:
        setPortraitKey(java.lang.String), setCustomPortraitHandling(boolean), PortraitProvider, DIY.FaceStyle
      • getPortraitSource

        public final java.lang.String getPortraitSource()
        Returns the portrait source identifier. This is equivalent to getPortrait(0).getSource().
        Returns:
        the portrait source
        See Also:
        getPortrait(int), Portrait
      • setPortraitSource

        public final void setPortraitSource​(java.lang.String source)
        Sets the portrait source. This is equivalent to getPortrait(0).setSource(source).
        Parameters:
        source - the portrait source
        See Also:
        getPortrait(int), Portrait
      • getPortraitImage

        public final java.awt.image.BufferedImage getPortraitImage()
        Returns the current portrait image as a bitmap. This is equivalent to getPortrait(0).getImage().
        Returns:
        the portrait image
        See Also:
        getPortrait(int), Portrait
      • getPortraitPanX

        public final double getPortraitPanX()
        Returns the horizontal position of the portrait. This is equivalent to getPortrait(0).getPanX().
        Returns:
        the x pan position
        See Also:
        getPortrait(int), Portrait
      • setPortraitPanX

        public final void setPortraitPanX​(double x)
        Sets the horizontal position of the portrait. This is equivalent to getPortrait(0).setPanX(x).
        Parameters:
        x - the x pan position
        See Also:
        getPortrait(int), Portrait
      • getPortraitPanY

        public final double getPortraitPanY()
        Returns the vertical position of the portrait. This is equivalent to getPortrait(0).getPanY().
        Returns:
        the y pan position
        See Also:
        getPortrait(int), Portrait
      • setPortraitPanY

        public final void setPortraitPanY​(double y)
        Sets the vertical position of the portrait. This is equivalent to getPortrait(0).setPanY(y).
        Parameters:
        y - the y pan position
        See Also:
        getPortrait(int), Portrait
      • getPortraitScale

        public final double getPortraitScale()
        Returns the scale factor of the portrait. This is equivalent to getPortrait(0).getScale().
        Returns:
        the scale factor
        See Also:
        getPortrait(int), Portrait
      • setPortraitScale

        public final void setPortraitScale​(double factor)
        Sets the scale factor of the portrait. This is equivalent to getPortrait(0).setScale(factor).
        Parameters:
        factor - the scale factor
        See Also:
        getPortrait(int), Portrait
      • clearAll

        public void clearAll()
        Clears the component by setting the name and comments to empty strings, resetting the expansion symbol key, marking all sheets as changed, and calling the handler scripts onClear function to clear the component elements defined by the script.
        Specified by:
        clearAll in interface GameComponent
        Overrides:
        clearAll in class AbstractGameComponent
      • computeIdealScaleForImage

        public double computeIdealScaleForImage​(java.awt.image.BufferedImage image,
                                                java.lang.String clipKeyType)
        Determine the ideal default scale for a portrait image so that the image completely covers the clip region.
        Overrides:
        computeIdealScaleForImage in class AbstractGameComponent
        Parameters:
        image - the image to compute the ideal scale for
        clipKeyType - use "portrait" or null for the portrait clip region, "marker" for the marker clip region
        Returns:
        the ideal scale for the image based on the portrait clip region
      • computeMinimumScaleForImage

        public double computeMinimumScaleForImage​(java.awt.image.BufferedImage image,
                                                  java.lang.String clipKeyType)
        Determine the ideal default scale for a portrait image so that the image just touches the clip edges in one dimension.

        This is overridden to use the portrait key to determine the clip region.

        Overrides:
        computeMinimumScaleForImage in class AbstractGameComponent
        Parameters:
        image - the image to compute the minimum scale for
        clipKeyType - use "portrait" or null for the portrait clip region, "marker" for the marker clip region
        Returns:
        the minimum scale for the image based on the portrait clip region
        See Also:
        setPortraitScaleUsesMinimum(boolean)
      • getNameField

        public javax.swing.text.JTextComponent getNameField()
        Returns the name field used to hold the name of the component. May be null.
        Returns:
        the text field that contains the component's name, as set by setNameField(javax.swing.text.JTextComponent)
      • setNameField

        public void setNameField​(javax.swing.text.JTextComponent nameField)
        Sets the field that contains the component's name. If set, edits in this field will automatically update the component's name, and the component's name will be copied to the field when copying the component state to the editor. Leave this set to null if you would like to handle editing the name yourself (for example, if you want separate given and family name fields).
        Parameters:
        nameField - the text field used to edit the component's name, or null
      • onClear

        public void onClear​(DIY diy)
        Calls the script's onClear function. This should not be called directly; instead, call clearAll(). Exceptions thrown by the script function will be caught and reported in the script console. Called when the user wants to reset the component to a blank state.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        onClear in interface Handler
        Parameters:
        diy - this component
      • create

        public void create​(DIY diy)
        Calls the script's create function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        create in interface Handler
        Parameters:
        diy - this component
      • createInterface

        public void createInterface​(DIY diy,
                                    DIYEditor editor)
        Calls the script's createInterface function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        createInterface in interface Handler
        Parameters:
        diy - this component
        editor - an editor created to edit the component
      • createFrontPainter

        public void createFrontPainter​(DIY diy,
                                       DIYSheet sheet)
        Calls the script's createFrontPainter function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        createFrontPainter in interface Handler
        Parameters:
        diy - this component
        sheet - the sheet used to paint the face
      • createBackPainter

        public void createBackPainter​(DIY diy,
                                      DIYSheet sheet)
        Calls the script's createBackPainter function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        createBackPainter in interface Handler
        Parameters:
        diy - this component
        sheet - the sheet used to paint the face
      • paintFront

        public void paintFront​(java.awt.Graphics2D g,
                               DIY diy,
                               DIYSheet sheet)
        Calls the script's paintFront function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        paintFront in interface Handler
        Parameters:
        g - a graphics context to draw the face with
        diy - this component
        sheet - the sheet used to paint the face
      • paintBack

        public void paintBack​(java.awt.Graphics2D g,
                              DIY diy,
                              DIYSheet sheet)
        Calls the script's paintBack function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        paintBack in interface Handler
        Parameters:
        g - a graphics context to draw the face with
        diy - this component
        sheet - the sheet used to paint the face
      • onRead

        public void onRead​(DIY diy,
                           java.io.ObjectInputStream objectInputStream)
        Calls the script's onRead function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        onRead in interface Handler
        Parameters:
        diy - this component
        objectInputStream - the object input stream being used to read the component
      • onWrite

        public void onWrite​(DIY diy,
                            java.io.ObjectOutputStream objectOutputStream)
        Calls the script's onWrite function. This should not be called directly. Exceptions thrown by the script function will be caught and reported in the script console.

        Subclasses may override this function to implement a DIY component as a subclass of DIY. In order to do this, all of the methods that make up the Handler interface must be overridden, except those in PortraitProvider.

        Specified by:
        onWrite in interface Handler
        Parameters:
        diy - this component
        objectOutputStream - the object output stream being used to write the component
      • toString

        public java.lang.String toString()
        Returns a string describing the component, including the handler script name and face style.
        Overrides:
        toString in class java.lang.Object
        Returns:
        a string describing this DIY component
      • clone

        public DIY clone()
        Description copied from interface: GameComponent
        Returns a deep copy of this game component. The default clone implementation provided by super.clone() will return a shallow copy of the object. This will correctly clone all of this instance's fields that have primitive types. It is then up to you to clone any object fields where the field is not of an immutable type. Images used to store portraits, although not technically immutable, are treated as immutable by Strange Eons. So long as you also follow this convention, you can save memory by sharing the shallow copy of the image.

        Debugging tip: One operation that makes use of the clone() method is the Spin Off command. If you apply this command, make changes to the copied component, redraw the original component, and notice that changes in the copy have carried over to the original, then you are using a shallow copy rather than a deep copy. (That is, you are sharing a reference to the same mutable object rather than making a copy of the mutable object during the cloning.)

        Specified by:
        clone in interface GameComponent
        Overrides:
        clone in class AbstractGameComponent
        Returns:
        a deep copy of this component
      • upgradeOldPropertyNames

        @Deprecated
        public final void upgradeOldPropertyNames()
        Deprecated.
        This should only be called in an onRead function when upgrading very old DIY components.
        This method can be called by DIY components that have been updated to use the style of property names introduced along with support for $-notation. It automatically converts old "x-" style property names to the new naming style. (For example, x-my-setting becomes MySetting.)
      • convertFrom

        public void convertFrom​(ConversionSession session)
        Description copied from interface: GameComponent
        Called on a component that is being converted into another component type. Based on the conversion strategy, the old component may modify the new component directly, or modify the conversion context, or do nothing. This method is called before calling #convertTo(GameComponent, ConversionContext) on the target, and before any automatic conversion steps.
        Specified by:
        convertFrom in interface GameComponent
      • convertTo

        public void convertTo​(ConversionSession session)
        Description copied from interface: GameComponent
        Called on the replacement component when converting a component to another component type. Based on the conversion strategy, the new component may modify itself directly, or modify the conversion context, or do nothing. This method is called after calling #convertFrom(GameComponent, ConversionContext) on the source, but before any automatic conversion steps.
        Specified by:
        convertTo in interface GameComponent
      • convertToComponentType

        public void convertToComponentType​(java.lang.String className)
        This method can be called by the DIY component if it wants to initiate conversion to another component type during onRead. The new type is assumed to belong to the same extension. If this is not the case, use #convertToComponentType(String, String) instead.
        Parameters:
        className - the class or script identifier to convert to
      • convertToComponentType

        public void convertToComponentType​(java.lang.String className,
                                           java.lang.String extensionName,
                                           java.lang.String extensionId)
        This method can be called by the DIY component if it wants to initiate conversion to another component type during onRead.
        Parameters:
        className - the class or script identifier to convert to
        extensionName - the name of the extension containing the new type
        extensionId - the UUID of the extension containing the new type