Friday, July 7, 2017

Abiathar API - Render planes

The image of a level or tileset in Abiathar is composed of planes stacked on top of each other. Though planes are not removed from the list of planes once added, they choose to render or not based on the user's instructions. Classic planes keep an image, which Abiathar's renderer draws where appropriate. Ephemeral planes draw directly on a graphics context. Planes implement either ILevelRenderPlane or ITilesetRenderPlane as appropriate. Both those interfaces are inherited from IRenderPlane, which has these members:

  • RenderNow gets whether the plane should be asked to show itself currently.
  • Image gets the image to render. This is not used for ephemeral planes.
  • ConsiderOffset gets whether Abiathar needs to position the plane according to the scroll position. This is not used for ephemeral planes.
  • PlaneName is the ID of the plane. By convention, IDs take the form of the extension name, a colon, and a plane title.
  • NeedsUpdate gets whether the plane should be asked to completely re-render itself at the next draw. Ephemeral planes should always return false.
  • HasTileinfo returns whether the plane displays tileinfo for the given simple plane (0 or 1).
  • SetStateAccessor is called so Abiathar can give the plane a state manager.
  • Render instructs the plane to prepare its Image. This is not used for ephemeral planes.
  • MarkDirty instructs the plane to mark itself as in need of a full update. This can be ignored by ephemeral planes.
  • IsEphemeral gets whether the plane uses ephemeral rendering.
  • RenderEphemeral instructs the plane to draw its contents on the given graphics with the given zoom level and offset. This is only used for ephemeral planes.
Level planes also have these members:
  • LevelPlane gets the simple plane (0 to 2) that the plane draws, or some other value if it does not correspond to any particular level plane.
  • SetRenderLevel is called to provide the plane with the level object it should render.
  • UpdateTile is called when a single tile is marked dirty. Return whether any changes were made to the image.
Tileset planes have these members in addition to the common plane members:
  • TilePlane is a historical artifact and is not used.
  • SetRenderPalette provides the plane with its tileset object.
  • UpdateSelectedTile is called when the selected tile for a plane changes. It provides the simple plane ID and the new tile ID.
  • TileViewSettingsChanged is not called by Abiathar.
To register a plane, add it to the Planes list of an AbiatharLevelViewStateInitializeEvent (for level planes) or an AbiatharTileViewStateInitializeEvent (for tileset planes) in the event bus.

Thursday, July 6, 2017

Abiathar API - Tools

Tools are the preferred method of providing functionality to Abiathar. Tool objects implement either IAbiatharLevelTool (for level tools) or IAbiatharTilesetTool (for tileset tools). These both inherit from IAbiatharTool, which has these members:

  • Name is the tool's name for display in the Tools menu.
  • Icon is the image to place on the Tools menu. This can be null if you do not want an icon.
  • ShortcutKey specifies the tool's keyboard shortcut. Key numbers are Windows Forms key codes. This can be null if the tool does not have a shortcut.
  • ShortcutText is the text to show on the right of the item in the Tools menu.
  • HandlesKeyPress returns whether the tool should receive key events while active.
  • KeyPress is called when a key is pressed. Return whether the press should be considered handled. This is only called if the tool handles key presses.
  • CanBeDefault returns whether it's acceptable for the user to set this tool as their default. For example, the Tile Placer can be the default level tool, but the Level Inspector cannot.
Level tools also have these members:
  • StartUse is called when the tool is switched to. It provides the current level.
  • SwitchLevel is called when the current level changes while the tool is active. It provides the new level.
  • Canceled is called when the tool is switched away from. It includes whether the cancel was initiated by the CancelTool method.
  • HandlesInLevelClick returns whether the tool should receive click events for the level.
  • InLevelClick is called when the user clicks in the level. It includes the coordinates and whether it is a right-click. This is only called if the tool handles clicks.
  • HandlesInLevelMouseMove returns whether the tool should receive mouse movement events.
  • InLevelMouseMove is called when the mouse is moved in the level. It includes the current mouse coordinates in tiles and whether the left and right buttons are being held down. This is only called if the tool handles mouse movement.
Tileset tools have these members in addition to the generic tool members, very similar to the level tool members but with tileset parameters instead of levels:
  • StartUse is like a level tool's StartUse.
  • SwitchSet is like a level tool's SwitchLevel.
  • Canceled is like a level tool's Canceled.
  • HandlesTileClick is like a level tool's HandlesInLevelClick.
  • TileClick is like a level tool's InLevelClick.
  • HandlesTileMouseMove is like a level tool's HandlesInLevelMouseMove.
  • TileMouseMove is like a level tool's InLevelMouseMove.
To register a tool, add it to the Tools list of an AbiatharRegisterToolsEvent (of IAbiatharLevelTool or IAbiatharTilesetTool, as appropriate) in the event bus.

Wednesday, July 5, 2017

Abiathar API - Undo/redo

A very important feature of Abiathar is the undo/redo history. This allows the user to reverse any mistakes they made without discarding all uncommitted changes. Extensions that alter levels, tileinfo, or project configuration must consider the undo history.

After making any change, extensions must either clear the undo history (ClearUndoStack on the state manager) or add the action to the undo stack with PushUndoStack. If these methods are not used, the undo stack may become corrupted, leading to inconsistencies and crashes. An undoable action object must implement IUndoableAction, which has these members:

  • Undo undoes the action.
  • Redo redoes the action.
  • Description gets a one-line description of the action for display in the Time Machine.
For your convenience, there is a SimpleUndoableAction class that combines Undo and Redo into one Perform method that takes a Boolean indicating whether to redo.

Tuesday, July 4, 2017

Abiathar API - Interacting with the UI

The ViewState property on the Abiathar state is very important for showing changes on the screen. It has these members:

  • GetTileImage returns the 16x16 image of the given tile in the given plane.
  • RerenderSelTiles refreshes the selected tile bay.
  • MarkLevelDirty marks the entire given level as in need of a re-render.
  • MarkPlaneDirty marks the given plane of the given level as in need of a re-render.
  • MarkTileDirty takes a level ID, plane, X, Y, new tile ID, and old tile ID, using them to update just that spot if necessary. This is much faster than invalidating an entire plane or level.
  • RerenderViewer updates the level/tileset viewer.
  • SetInfoText sets the tool status text in the lower right.
  • MoveToExtantLevel switches to a level that exists. Call this after deleting a level.
  • ShowingTileset returns the current tileset, or nothing if no tileset is visible at the moment.
  • ShowingLevel returns whether a level is visible.
  • LevelViewOffset returns the X and Y scroll position in the given level. This might throw an exception if the level is not cached.
  • TileViewOffset returns the Y scroll position for the given tileset.
  • VariableTilesetWidth is a historical artifact and always returns false.
  • Config returns the editor configuration. This is probably not useful to any extension.
  • GetPlane returns the plane object for a given level ID and plane name.
  • GetTilePlane does likewise, but for tilesets.
  • ShowTip puts up a "did you know?" in the lower right.
  • SetContextHelpText sets the contextual help text.
  • RefreshMouse creates a mouse movement event at the location of the mouse cursor.
  • SetMouseLocHighlight enables or disables highlighting the tile under the mouse. This is ignored if the user doesn't have that particular Keen:Next nostalgia setting on.
  • GetNumberDisplay formats a number in accordance with the user's numeric base preference for that kind of data.
  • ZipToPoint places the given level position under the mouse cursor. If StoreAsLast is true, the Zip To window will suggest it automatically next time that window is shown.
The UI processing state object (returned by UiProcessingState on the state manager) has these properties:
  • TranslatedClick returns whether the current click event is actually a translation of some other process.
  • DragTranslationActive returns whether the current level or tile tool has some kind of click translation enabled.
Drag translation is activated with the SetDragTranslationMode method on the state manager. You have these options:
  • NoTranslation doesn't do any automatic translation of drags into clicks.
  • ClickOnEveryStep produces a click on every tile the mouse drags over.
  • ClickOnDragEndpoints produces at most two clicks for every drag: one at the start and one at the end.

Monday, July 3, 2017

Abiathar API - Interacting with tilesets

Abiathar supports four tilesets at the moment: background, foreground, infoplane, and combined foreground/infoplane. The IDs for these are set by the Tileset enumeration. Tileset objects returned by the CurTileset and TilePalette properties of the state manager have these members:

  • TileCount returns the number of tiles in the palette.
  • Width and Height are the dimensions of the palette in tiles.
  • TileIDAt returns the ID of the tile at the given X and Y, or nothing if there's no tile there.
  • TilePos returns the X and Y in tiles of the given tile ID, or nothing if that tile isn't in the tileset.
  • TechnicalCount returns how many tiles the actual graphics source has of this type. Since there are only two kinds - unmasked and masked - all sets except the background have the same technical count.
  • ViewStart is the ID of the first tile in the tileset.
  • Includes returns whether the tileset has tiles useful for the given normal plane (0 to 2).
  • ID returns the ID of the tileset.
The tileinfo registry (acquired through TileinfoAccessor on the state manager) has these properties:
  • ForegroundTileProp gets or sets the Abiathar Tile Property ID for the given foreground tile. To interpret these values, use the TileinfoHelper class. To create such values, use PropertyAssemblyHelper.AssembleForegroundProperty.
  • BackgroundTileProp does likewise, but for the background. To interpret, use the BackgroundAnimHelper class. To create, use PropertyAssemblyHelper.AssembleBackgroundProperty.
  • EditableTileinfo returns whether the current project's tileinfo is editable. If it's not, changes to tileinfo will be ignored.

Sunday, July 2, 2017

Abiathar API - Interacting with levels

The LevelGen property on IAbiatharState allows extensions to create levels. The level generator has these functions:

  • NewLevel takes the width, height, and name and produces a level object with those dimensions.
  • NewFromProps creates a new level with the same dimensions and properties as an existing one.
  • NewFromMetadata creates a new blank level with the given width and height, but the other properties provided by an existing level.
You are responsible for making sure the dimensions you supply are within the size restrictions returned by the SizeRestrictions property of the state manager.

Level objects have these properties:
  • Data gets or sets the tile ID at the given X, Y, and plane.
  • Name is the level's name.
  • Signature is the signature written into the level file next to the level. This might be ignored, depending on the level format.
  • Width and Height are exactly what they claim to be.
  • ExtraData gets or sets the value of an extended data field. This is only useful on extended level formats.
Level sets (as returned by the state manager property Levels) have these members:
  • Count is the number of present levels.
  • Add adds a new level object with the given ID.
  • Delete removes the level with the given ID.
  • At gets or sets the level at the given ID. Instead of using this to replace a level, use ReplaceLevel on the state manager.
  • Clear deletes all levels.
  • List gets a list of all present IDs.
  • Create returns a new level object with the given width and height. Use the level generator instead.
  • Exists returns whether there is a level with the given ID.

Saturday, July 1, 2017

Abiathar API - Interacting with Abiathar

Almost all interactions an extension has with Abiathar provide an IAbiatharState object. This lets your extension work with Abiathar objects. Here are all the members of that interface:

  • LevelGen provides a level generator, which you can use to create new level objects.
  • Levels provides the level set, which has methods that allow you to inspect, add, and remove level objects.
  • TilePalette produces a tileset object for the given tileset ID.
  • CurTileset returns the currently active tileset object.
  • ViewState returns the view state manager, which you can use to control the UI.
  • TileinfoAccessor provides the tileinfo manager, which you can use to get and set tile's properties.
  • FastMode returns whether Abiathar is in High Speed Mode. In this mode, you should skip fancy graphical effects and not bother with tracking the undo/redo history.
  • CurLevelID returns the current level ID.
  • CurLevel returns the current level object.
  • SelTiles returns the three-long array of selected tile IDs, one for each plane.
  • PlaneStates returns the three-long array of plane states (Active, Locked, Hidden).
  • CurTool returns the current level tool.
  • CurTileTool returns the current tileset tool.
  • FileConfig returns the dictionary of configuration sections.
  • UiProcessingState returns an object that lets you query the current UI settings.
  • SizeRestrictions gets the level format's level size restrictions.
  • ExtraDataFields returns the level format's list of extra data fields. This will only be useful on extended level formats.
  • LevelGenre returns a level-format-defined string.
  • MarkChangesMade sets the levels as modified so Abiathar will warn before exiting.
  • PushUndoStack adds an undo history entry to the timeline. This does nothing if High Speed Mode is on.
  • ClearUndoStack purges the undo timeline.
  • DestroyLevelViewState deletes the cached images of the level with the given ID. Call this when removing a level.
  • InitializeLevelViewState sets up all the planes of the level with the given ID. Call this when adding a new level.
  • ReplaceLevel replaces the level with the given ID with the level object provided.
  • CancelTool cancels either the current level tool or the current tileset tool (depending on whether TileTool is true). The tool may be restarted but left active if HardAbort is false. Call this when a tool has finished an operation.
  • SetTool sets the current tool (level or tileset, as indicated by TileTool) to the given tool object.
  • NotifySelTileChange broadcasts a change in the selected tile for the given plane. Call this after changing the array of selected tiles.
  • NotifyTileinfoChange broadcasts a change in a plane's tileinfo, 0 for background, 1 for foreground.
  • SetDragTranslationMode sets how Abiathar will translate mouse drags for your tool. Supply whether your tool is a tileset tool.
  • DoVisibleLongOperation executes an action on a separate thread and shows a dialog to the user while it runs.
  • IsLevelCurrent returns whether the given level object is the current level.
  • GetExtension returns a loaded extension by name, or null if it cannot be found.
The properties that have to do with the current level or tileset only make sense if a level or tileset is being shown. Therefore, it is only safe to call them from a tool of that type, since a level tool can only run while a level is shown, and likewise for tileset tools and tilesets.