Skip to main content
Framework Movable

Movable Plugin System

This framework provides the functionality for plugins to draw display panels that players can interact with to drag, resize, and toggle visual elements on or off in-game. It also generates ICustomizer files that save area positions, dimensions, enabled states, and a custom string for cross-session persistence.

Unified Modification

Each plugin doesn't have to do it's own handling of mouse or key presses, and it doesn't have to define yet another hotkey for toggling stuff on or off, it can just focus on drawing data on the screen. A plugin that implements the IMovable interface will gain the ability to create movable areas that can be dragged around the screen and resized, and all of that code is handled behind the scenes by this library. All of the positions, dimensions, and movement delta values necessary to draw elements on the screen are provided to the Movable plugin via a PaintArea method, which works like PaintTopInGame.

Drag (or Hotkey) to Move

Press F12 to toggle Edit Mode on, which shows outlines of all the movable plugin display areas on the screen. You can drag and drop them freely while in this mode.

Because clicking around on the screen causes your character to move around or perform actions, I added the ability to specify hotkeys the plugin will handle as if you had clicked instead. To enable this or change its hotkey, set or change SimulateLeftMouseClick and SimulateRightMouseClick properties from plugins\Razor\Click\ClickEventHandler.cs. The default values of E and R are commented out on lines 57 and 58.

Drag (or Hotkey) to Resize

While in Edit mode, hovering over a resizable plugin area shows little triangle corners on the bottom left and bottom right of the outline. Hovering over them will show what sort of resizing you can do. There are 4 Resize modes that plugins can specify: ResizeMode.On (free resize), ResizeMode.FixedRatioResizeMode.Horizontal, and ResizeMode.Vertical. Not all areas are resizable, just depends on the plugin and whether or not it does the extra size calculations.

Toggle Off or On (Hotkey)

While in Edit mode, press Ctrl + X while you have a plugin area selected or hovered over to toggle that area display on or off.

Undo (Hotkey)

While in Edit mode, press Ctrl + Z while you have a plugin area selected or hovered over to undo drag or resize actions applied to it.

Save Settings to File

Using the save-to-file hotkey (default: Ctrl + S) will generate an ICustomizer plugin file with your modified settings in the correct location. This will allow you to retain the changes you made when you load TurboHUD next time.

Changing the position, size or on/off state of any of the movable areas will automatically generate an ICustomizer file at TurboHUD\logs\MovablePluginConfig.txt

In case you forget to use the save-to-file hotkey, this file is there so that you can optionally restore your changes from the last aborted TurboHUD session by copying the txt file from your TurboHUD\logs folder to TurboHUD\plugins\User\MovablePluginConfig.cs.

For plugin authors, setting a MovableArea's ConfigFileName property will write its config changes to the specified file instead. Leaving it blank will result it being written to the default "MovablePluginConfig" file.


All of these are configurable, with the variables mostly located in TurboHUD\plugins\Razor\Movable\MovableController.cs.

  • ToggleEditMode (F12) - toggle Edit Mode on or off
  • SimulateLeftMouseClick (none) - because when you click around the screen, D3 moves your character around and interacts with the game world, it's probably easier just to press a hotkey to simulate a mouse click - edit this in TurboHUD\plugins\Razor\Click\ClickEventHandler.cs
  • SimulateRightMouseClick (none) - because when you click around the screen, D3 moves your character around and interacts with the game world, it's probably easier just to press a hotkey to simulate a mouse click - edit this in TurboHUD\plugins\Razor\Click\ClickEventHandler.cs
  • ToggleEnable (Ctrl + X) - toggle display on or off
  • ToggleGrid (Ctrl + G) - toggle placement grid display on or off
  • HotkeyUndo (Ctrl + Z) - undo movement or resize
  • HotkeyUndoAll (Ctrl + 0) - undo all movements or resizes (ctrl + ZERO)
  • HotkeySave (Ctrl + S) - save config file now (this is separate from auto-save, but is still subject to the logging limitations of your TH version)
  • HotkeyCancel (Esc) - cancel your current move or resize action
  • HotkeyPickupNext (Right) - cycle forwards through all areas under your cursor and pick up the next one
  • HotkeyPickupPrev (Left) - cycle backwards through all areas under your cursor and pick up the previous one

Visibility Checking

Movable plugins are rendered during the ClipState.BeforeClip step by default, and it will properly disable rendering, click and hotkey events as necessary while obscured by (sharing the same space as) most visible game interface elements.

Custom Handlers

The Movable system has its own optional handlers for hotkeys and click events that occur while the mouse cursor is hovering over a visible MovableArea. This makes it simple to code actions like "do something when you click on this MovableArea" or "do something when you use a hotkey while hovering over this MovableArea."
  • IMovableKeyEventHandler - hotkey events that occur when your mouse is hovering over a MovableArea
  • IMovableLeftClickHandler - left mouse click events that occur when your mouse is hovering over a MovableArea
  • IMovableRightClickHandler - right mouse click events that occur when your mouse is hovering over a MovableArea
  • IMovableDeleteAreaHandler - for notifications of MovableArea.DeleteOnDisable deletions


I separated the optional plugins that implement the Movable plugin system from the core download so that they can be updated separately. The only exception to this is my Menu Plugin, which already includes the latest version of Movable. Any plugins I write that use the Movable Plugin system will be tagged with the Movable label.


Put the folders in the archive into your TurboHUD directory. The files should be in the following locations when you're done:

TurboHUD \ plugins \ Razor \ Click \ ClickEventHandler.cs
TurboHUD \ plugins \ Razor \ Click \ ILeftClickHandler.cs
TurboHUD \ plugins \ Razor \ Click \ IRightClickHandler.cs
TurboHUD \ plugins \ Razor \ Hotkey \ HotkeyEventHandler.cs
TurboHUD \ plugins \ Razor \ Hotkey \ IHotkeyEventHandler.cs
TurboHUD \ plugins \ Razor \ Log \ ITextLogger.cs
TurboHUD \ plugins \ Razor \ Log \ TextLogger.cs
TurboHUD \ plugins \ Razor \ Movable \ IMovable.cs
TurboHUD \ plugins \ Razor \ Movable \ IMovableDeleteAreaHandler.cs
TurboHUD \ plugins \ Razor \ Movable \ IMovableKeyEventHandler.cs
TurboHUD \ plugins \ Razor \ Movable \ IMovableLeftClickHandler.cs
TurboHUD \ plugins \ Razor \ Movable \ IMovableRightClickHandler.cs
TurboHUD \ plugins \ Razor \ Movable \ MovableArea.cs
TurboHUD \ plugins \ Razor \ Movable \ MovableController.cs
TurboHUD \ plugins \ Razor \ Movable \ ResizeMode.cs
TurboHUD \ plugins \ Razor \ Util \ UIOverlapHelper.cs

Then (re)start TurboHUD.


February 17, 2022
  • removed the debug dependency to Razor.Label
  • removed IPluginManifest dependency declaration for Razor.Click.*
  • converted my mouse click detection and blocking implementation to use the new TurboHUD functions
September 8, 2021
  • implemented IPluginManifest to add plugin metadata
July 14, 2021
  • added custom blocking areas to the MovableArea clip checks
July 11, 2021
  • converted manual save to automatic save
June 13, 2021
  • implements ILeftBlockHandler to block left mouse clicks when interacting with MovableAreas in Edit Mode
May 17, 2021
  • paints MovableAreas that are attached to the cursor even if they are being dragged over obstructing UI areas
May 8, 2021
  • converted the manual file save hotkey action to immediately save the config file to the plugins\User directory, in addition to the usual log backup file writing
  • edge optimization: if no Movable plugins are registered, MovableController will no longer do any other Paint checks besides drawing grid in Edit Mode
May 6, 2021
  • fixed exception from UIOverlapHelper when its checking functions are called before the plugin has initialized its UI references
April 30, 2021
  • updated ClickEventHandler to no longer have E and R set as simulate click hotkeys by default for more out-of-the-box compatibility
April 28, 2021
  • UIOverlapHelper reference in MovableController is now publicly readable so that Movable plugins can easily utilize it for custom UI overlap checks without having to save their own reference to it
April 24, 2021
  • added IMovableDeleteAreaHandler to patch in the ability to optionally notify owner IMovables of associated area deletion
  • rewrote the code for DeleteOnDisable
April 20, 2021
  • fixed resizing from the left side (again)
April 19, 2021
  • separated ui overlap detection code into its own helper class, UIOverlapHelper
April 17, 2021
  • hotkeys are now filtered through the Razor.Hotkey handler and no longer require Edit Mode
  • added a click handler system so that Movables can respond to click events that happen specifically within their movable areas while not in Edit Mode
April 3, 2021
  • implemented ITextLogger for delayable, queued TextLog writing
February 1, 2021
  • custom clipping with mail ui because it doesn't respect ClipState.BeforeClip
  • added Journal UI to left ui check list
  • fixed some clip detection and manual clipping issues
January 27, 2021
  • Movable areas can now specify a config file name, and MovableController will now write those areas' config data to the specified config file instead of the default one -> any Movable plugin can now specify its own separate config files to be generated (functionality added for PartyTracker)
  • Movable areas can now specify a custom string value that can be used for config or whatever kind of data storage that gets saved to the config file
January 22, 2021
  • added mail ui to should-be-clipped-but-isn't list
January 16, 2021
  • separated leftuis into two categories: leftuis (covers all) and leftshortuis (covers a little less than all)
January 14, 2021
  • added centeruis and check inventory separately from rightuis (rightshortui)
  • added inventory details pane to clip area detection lists
January 9, 2021
  • added chat text prompt to clip area detection lists
December 27, 2020
  • added the tooltip uielement to the clip area detection lists
December 24, 2020
  • stop rendering area if a text prompt (e.g. Armory save text prompt) covers it
  • stop rendering area if a secondary menu covers it (kanai's recipes, kanai's powers selection)
December 23, 2020
  • stop rendering or accepting input for areas when they are underneath important, visible game menu elements
December 20, 2020
  • fixed resizing from the left side (again)
December 15, 2020
  • added the ability to restore dynamically created areas from config (needed the area name rather than the area index to be saved)
  • deletion of temporary areas now trigger a config write
November 29, 2020
  • fixed Grid lines being redrawn multiple times, once for every Movable plugin
  • shifted EditMode plugin titles that would be draw above the top of the screen to the top of the screen instead for visibility
  • updated MyMovablePluginTemplate.txt with a clarification of which RectangleF class to use (System.Drawing, not SharpDX) and an example of checking Edit Mode state
August 18, 2020
  • Grid brush drawing now uses both light and dark brushes so that it shows up for all visual atmospheres
  • Lowered the opacity of unselected area titles slightly
August 1, 2020
  • Fixed FixedRatio resizing calculations
  • Added subtle placement-assist grid lines that can be toggled off and on while in Edit Mode (default hotkey: Ctrl+G)
  • By request, implemented an Undo All hotkey
July 28, 2020
  • Fixed errors caused by config data if the localization of position and dimension numbers resulted in decimal points being written with commas (now it rounds to the nearest integer pixel)
July 27, 2020
  • Removed unused private variables
July 26, 2020
  • Undoing while in the middle of a resize action will now cancel the resize
  • Renamed ModifyMode to EditMode
July 25, 2020
  • IMovable now extends IPlugin
July 23, 2020
  • Moved the code that clears area out Cursor, Resize and Hovered area globals from DeleteArea to the point at which areas are actually deleted
July 22, 2020
  • Added SnapTo(x,y) for implementing snap to location (x,y) behavior for area currently picked up
  • Fixed MovableController.DeleteArea(area) now clears area out of Cursor, Resize and Hovered area globals
  • Added different outline color for DeleteOnDisable flagged areas
  • Fixed Ctrl+C to be able to put down area when outside of Modify mode
July 21, 2020
  • Added area.SaveToConfig check to ToggleArea before flagging for a config update
  • Fixed missing drag resizing checks on put down for preventing negative dimensions
  • Removed key event passing to IMovableKeyEventHandler (too narrow of a use case to be worthwhile?)
July 20, 2020
  • Added a reference to MovableController in PaintArea function signature so that it is less complicated for PaintArea code to check whether or not the specified MovableArea is on the cursor, being resized or hovered and draw its contents accordingly
  • Undo now can be applied to the current area picked up on the cursor
  • Added IMovableKeyEventHandler for IMovable plugins that want to watch for custom key events when selected in Modify Mode
  • Added MovableController.DeleteArea with a deletion queue
July 19, 2020
  • Removed unused variable AllowDragAndDrop
  • Fixed hotkey selection of next and previous movable area at cursor
July 18, 2020
  • Clear HoveredPluginArea when Outline mode is toggled off
  • Fixed NullPointerException that happens when TH is loaded while in menus and then you enter a game (note: initialization has to wait until you are in a game for the first time, otherwise OnRegister calls that reference existing UI element positions may return 0 because TH hasn't started collecting data about their positions yet)
  • Fixed queued config file generation not triggering after valid logging conditions are detected
  • Added mouse hint symbols for ResizeMode.Horizontal and ResizeMode.Vertical
  • Moved Changelog into its own file because TH was detecting its content as suspicious code
July 17, 2020
  • Changed Resizable on/off bool into a ResizeMode setting to include special calculations for Fixed Ratio, Horizonal or Vertical locked resizing
  • Added highlighting behavior for improved outline selection visibility
July 15, 2020
  • Automatic config file generation (if enabled) now attempts to save the log file again when a valid logging state is detected (not in a special area or difficulty above Torment 1 or in a game) if the original generation was triggered in an invalid logging state
July 14, 2020
  • Added full history Undo for moving and resizing MovableAreas
July 13, 2020
  • Added the ability to resize MovableAreas by dragging the bottom left or bottom right corners
July 12, 2020
  • Added the ability for MovableAreas to be drawn at different clipstates, not just BeforeClip
July 11, 2020
  • Removed the dependences on extending BasePlugin and implementing ICustomizer to streamline implementation in other plugins
  • Added config fields for width and height modification
July 2, 2020
  • Renamed the Floater framework to the Movable framework
  • separated click detection into its own generic handler
  • changed the config file generation to use ConfigFileName as the class name
April 17, 2020
  • Initial release

For Plugin Authors

If you would like to have your plugin use the Movable system, I've included a heavily commented example plugin template in the download to explain how to implement it.

Works with Diablo 3 patch, TurboHUD v21.12.8.0, API v9.2


  1. Does this work as of today 17th of December 2021? Got exceptions 2 when started

    1. It works if you comment out line 19 in TurboHUD\plugins\Razor\Movable\MovableController.cs, I accidentally left a call to a library I was using for debugging in there (oops!). Otherwise, you can just use the Menu Plugin System package which includes this Movable framework in the download. Thanks for the heads up about the issue.

  2. hi, tried to run and got an exception, can you help?

    TurboHUD\Plugins\Razor\PartyHealthTracker.cs(909,49) : error CS1061: 'IWorldCoordinate' does not contain a definition for 'Window' and no accessible extension method 'Window' accepting a first argument of type 'IWorldCoordinate' could be found (are you missing a using directive or an assembly reference?)
    TurboHUD\Plugins\Razor\PartyHealthTracker.cs(909,118) : error CS1061: 'IWorldCoordinate' does not contain a definition for 'Window' and no accessible extension method 'Window' accepting a first argument of type 'IWorldCoordinate' could be found (are you missing a using directive or an assembly reference?)

    1. The new version of TH removes IWorldCoordinate.Window, so you need to change the code at the line mentioned (909) that looks like "____.Window" to "Hud.Window"


Post a Comment