[New Wiki] How to Make Custom UMG Components for Use In UMG Designer!

Dear Community,

In my newest tutorial I show you how you can make your own custom UMG components that utilize custom render code to make completely new components that you can edit right in the UMG Designer!


Here's a video demonstrating my first custom UMG component! Notice how my Slate C++ code works with UMG's render transform system, making animation and render transformations work perfectly!

This video is of my [in-game AI editor for Abatron](!

Wiki Tutorial With Full C++ Source Code

I provide you with the entire C++ code for my custom UMG component shown in the video above!

Rama’s Wiki on Custom UMG Components With Custom Render Code

**Custom Slate C++ Render Code**

Here's the custom Slate render code that I wrote that works with UMG's Render Transform system!


int32 SSoftEdgeImage::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
	SCOPE_CYCLE_COUNTER( STAT_SlateOnPaint_SSoftEdgeImage );
	const FSlateBrush* ImageBrush = Image.Get();

	if ((ImageBrush != nullptr) && (ImageBrush->DrawAs != ESlateBrushDrawType::NoDrawType))
		const bool bIsEnabled = ShouldBeEnabled(bParentEnabled);
		const uint32 DrawEffects = bIsEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

		const FColor FinalColorAndOpacity( InWidgetStyle.GetColorAndOpacityTint() * ColorAndOpacity.Get().GetColor(InWidgetStyle) * ImageBrush->GetTint( InWidgetStyle ) );

		//For Thickness
		for (int32 v = 0; v < Thickness; v++ ) 
			//Adjusted Local Size
			FVector2D AdjustedSize = 
					AllottedGeometry.GetLocalSize().X - v*2,
					AllottedGeometry.GetLocalSize().Y - v*2
                        //Local Size and Translation  
                        FPaintGeometry PaintGeom =
					FVector2D(v,v),		//Local Translation
					AdjustedSize,		//Local Size
					1				//Local Scale
				OutDrawElements, 		//Out
				PaintGeom, 			//Paint Geom
				ImageBrush, 			//Brush
				MyClippingRect, 			//Clip
				FinalColorAndOpacity 		//Color and Opacity

		} //For loop
	return LayerId;





OPTIONAL_BIND and delegates don’t have anything to do with having values update in the designer when the property is changed. That’s handled by the call to SynchronizeProperties, you push all the latest values to the Slate widget. The only reason to have OPTIONAL_BIND and the delegates is if you want to support property or function binding for that property on the widget at runtime.

It would be much more efficient to do this in a material. It looks like your slate code is going to end up rendering hundreds of quads on top of each other in order to do this.

Ahhh great to have that clarified! I’ve updated the wiki to make it clear that the delegate part is optional and not required to get the live updates in the Designer.

Lovely to hear from you Nick! Thanks for the input!

I am currently working on some ideas for a UMG widget that could not be done more effectively with a simple masked material, here are some of my ideas!

All of these would be programmatically generated from USTRUCT data at the end of a game / match.

  1. A Pie chart (number of sections determined by the USTRUCT data)

  2. A line plotter / option to shade everything below the line

  3. A scatter point plotter

Generating the above from runtime gathered data would be really neat, and this wiki provides people with the framework needed to draw such elements using custom Slate render code!

Have fun today Nick!

Thanks for UMG!


Rama, I’ve been working on my own custom button. I noticed in your video that the Thickness variable had a Bind option next to it in the editor. I was curious as to how you achieved that. I’ve been trying to get an FName variable of mine to be bindable, but I haven’t had any luck.