Garry's Mod Wiki

Derma Skin Creation

Introduction

As a developer you may be familiar with PANEL:Paint and PANEL:PaintOver. They are functions to draw your Derma objects. But one day you wanted to make your own Derma design. You may think that redrawing is too complicated: surface, draw, render. So many functions, aren't they? Is there a way to make it easier and fancy? Yes, this page will show you how to create your own Derma Skin. Exactly same method uses default Derma and it's defined in Lua.

How Derma skins work?

First thing to know, they're located in "garrysmod/lua/skins/". Default Derma skin is in "default.lua".

It contains UV texture mapping, Color definitions and Derma Hooks.

UV mapping is possible through GWEN. Some GWEN functions require a IMaterial in last argument, but it can be empty: GWEN will use SKIN.GwenTexture variable instead. Default skin texture can be found in Garry's Mod .vpk file in "materials/gwenskin/gmoddefault.png".

Inside file there're bunch of Derma Hooks. They're used in conjunction with derma.SkinHook (used in Derma_Hook).

Example

This is in "default.lua".

function SKIN:PaintFrame( panel, w, h ) if ( panel.m_bPaintShadow ) then -- This is DFrame shadow local wasEnabled = DisableClipping( true ) self.tex.Shadow( -4, -4, w+10, h+10 ) -- This is drawing function, that contains a piece of our texture DisableClipping( wasEnabled ) end if ( panel:HasHierarchicalFocus() ) then -- Checks if DFrame is in focus and decide how to paint it self.tex.Window.Normal( 0, 0, w, h ) -- This is drawing function, that contains a piece of our texture else self.tex.Window.Inactive( 0, 0, w, h ) -- This is drawing function, that contains a piece of our texture end end

And this is in "lua/vgui/dframe.lua" where DFrame is defined.

function PANEL:Paint( w, h ) -- ... derma.SkinHook( "Paint", "Frame", self, w, h ) -- This creates hook to derma library, derma library is connected to our skin -- ... end

Last thing that skin file does is adding skin to Derma skins list. This action is done by derma.DefineSkin.

Preparing to create Derma skin

  1. Get Adobe Photoshop
  2. Extract "materials/gwenskin/gmoddefault.psd" (You can do this with GCFScape)
  3. Copy code (or file) from "lua/skins/default.lua"
  4. Create lua file in "lua/skins/". For this tutorial we will name it "myskin.lua".
  5. Create lua file in "lua/autorun/". You can name it how you want it, just make it unique, for example "myskin_include.lua".

Code for myskin_include.lua

if SERVER then AddCSLuaFile("skins/myskin.lua") else include("skins/myskin.lua") end

This file adds our skin to whitelist for server and includes for client on load.

Reference

SKIN

Table SKIN is a global variable. It's made global to work with GWEN.


derma.DefineSkin(skin name, skin description, SKIN table)

derma.DefineSkin( "Default", "Made to look like regular VGUI", SKIN )

This function will add your skin to list of all Derma skins.


derma.GetSkinTable()

for k,v in pairs(derma.GetSkinTable()) do print(k) end -- Prints all defined skins


derma.RefreshSkins()

This function will clear cache from Derma objects and set their skin again.

Tester snippet

To test out your Derma skin you can use this snippet.

concommand.Add( "derma_setskin", function(_,_,args) if GetConVar("sv_allowcslua"):GetInt() == 0 then return end for k,v in pairs(vgui.GetWorldPanel():GetChildren()) do v:SetSkin(args[1]) end end,nil,"Sets skin for all Derma objects.") local function deepskin(children,skin) for k,v in pairs(children) do v:SetSkin(skin) if #v:GetChildren() != 0 then deepskin(v:GetChildren(),skin) end end end concommand.Add( "derma_deepsetskin", function(_,_,args) if GetConVar("sv_allowcslua"):GetInt() == 0 then return end deepskin(vgui.GetWorldPanel():GetChildren(),args[1]) end,nil,"Forces skin set for all Derma objects and their children.") concommand.Add( "derma_updateskin", function() if GetConVar("sv_allowcslua"):GetInt() == 0 then return end for k,v in pairs(derma.GetSkinTable()) do if v.GwenTexture then local tex = v.GwenTexture:GetTexture("$basetexture") if tex then tex:Download() end end end derma.RefreshSkins() end,nil,"Updates skins for all Derma objects.")

Derma objects can't update themselves because skin that they used is cached. Due to skins are being cached, Derma objects can't update themselves while you're editing. So we need to clear cache by typing command derma_updateskin. Also its material can't update itself, to fix that, it uses ITexture:Download.

Function derma_setskin skin name allows you to apply Derma skin on all Derma object through the console. If some panels didn't update use derma_deepsetskin skin name.

For safety, you can't use these functions when sv_allowcslua is 0. You can remove this check if you don't forget to remove tester later. To test your skin you can type derma_controls to preview.

Part One: SKIN variables

SKIN table has a lot of variables. These are for info.

SKIN variables Information variables
PrintName My New Skin Name for your skin to display
Author Garry Newman Author of the skin
DermaVersion 1 Version of the skin
GwenTexture Material( "gwenskin/GModDefault.png" ) Texture path of the skin. This is used to draw Derma objects. This is internally used by GWEN.

Next you will see lots of Color variables. But not all of them are actually visible in game.

This list contains variables which were tested for changes.

SKIN variables Color variables
colTextEntryText Color( 20, 20, 20 ) Used for typed text color in DTextEntry and it's derivatives <note>Color can display incorrectly in game.</note>
colTextEntryTextHighlight Color( 20, 200, 250 ) Used for highlight color in DTextEntry and it's derivatives <note>Color can display incorrectly in game.</note>
colTextEntryTextCursor Color( 0, 0, 100 ) Used for cursor color in DTextEntry and it's derivatives
colTextEntryTextPlaceholder Color( 128, 128, 128 ) Used for SetPlaceholderText color in DTextEntry and it's derivatives <note>Color can display incorrectly in game.</note>

Column "In game" note: Right filled square represents real color. Left screenshot represents in-game render.

Other Color variables doesn't work because Derma objects use texture instead.

ULX uses SKIN.text_dark for some labels

Part Two: UV Texture

Named Textures

UV mapping zones. Can be found in .psd file in folder "Overlay".

Even in UV texture not all of textures are used in GMod!
List of named layers (From left top to right bottom)
Window (In Focus) Window - Active Texture of DFrame when HasHierarchicalFocus is true
Window (Out Focus) Window - Active (copy) Texture of DFrame when HasHierarchicalFocus is false
Generic Panel (Only left top is used) Panels - Generic Panel - Normal Texture of DPanel by default. This texture can be colored by SetBackgroundColor
Btn Nrml Buttons - Regular Texture of DButton when IsHovered is false and IsDown is false
Btn Hvr Buttons - Hovered Texture of DButton when IsHovered is true and IsDown is false
Btn Dsbld Buttons - Dead Texture of DButton when IsEnabled is false
Btn Down Buttons - Down Texture of DButton when IsDown is true
Chk Buttons - Checkbox - Enabled Textures of DCheckBox when IsEnabled is true
Chk Dsbld Buttons - Checkbox - Disabled Textures of DCheckBox when IsEnabled is false
Expnd Buttons - Tree Textures of DExpandButton
Tree Background Panels - Tree Panel Texture of DTree. This texture can be colored by SetBackgroundColor
Mnu rght Menu - Right Arrow Texture of Arrow in AddSubMenu option <note>DMenu doesn't derive panel's skin when called by DermaMenu. So it will be always "Default" skin. Works only when you set skin for it when it's visible or in DMenuBar.</note>
Menu Strip Menu - MenuStrip Texture of DMenuBar <note>DMenu doesn't derive panel's skin when called by DermaMenu. So it will be always "Default" skin. Works only when you set skin for it when it's visible or in DMenuBar.</note>
Menu Background Menu - With Border Texture of DMenuOption when GetDrawColumn is true <note>DMenu doesn't derive panel's skin when called by DermaMenu. So it will be always "Default" skin. Works only when you set skin for it when it's visible or in DMenuBar.</note>
Menu BG No Border Menu - Without Border Texture of DMenuOption when GetDrawColumn is false <note>DMenu doesn't derive panel's skin when called by DermaMenu. So it will be always "Default" skin. Works only when you set skin for it when it's visible or in DMenuBar.</note>
Menu Selected Menu - Hover Texture of DMenuOption when IsHovered is true <note>DMenu doesn't derive panel's skin when called by DermaMenu. So it will be always "Default" skin. Works only when you set skin for it when it's visible or in DMenuBar.</note>
Text Entry Normal Text Entry - Normal Texture of DTextEntry when IsEditing is false
Text Entry Focused Text Entry - Focus Texture of DTextEntry when IsEditing is true
Text Entry Disabled Text Entry - Disabled Texture of DTextEntry when IsEnabled is false
Scroller Track V Scrollbar - Vertical Texture of DVScrollBar track
VScrollbar - Normal Scrollbar - Vertical Texture of DVScrollBar.btnGrip when IsHovered is false and IsDown is false
VScrollbar - Hovered Scrollbar - Vertical Texture of DVScrollBar.btnGrip when IsHovered is true and IsDown is false
VScrollbar - Pressed Scrollbar - Vertical Texture of DVScrollBar.btnGrip when IsDown is true
VScrollbar - Disabled Scrollbar - Vertical Texture of DVScrollBar.btnGrip when IsEnabled is false
Tab Panel BG Tabbed - Body Texture of DPropertySheet where GetActiveTab is docked
Tab Top Tabbed - Active Texture of DTab when IsActive is true
Unfcs Top Tabbed - Inactive Texture of DTab when IsActive is false
List Box ListBox - Background Texture of DListBox. This class is deprecated, but it's still in game
This list contains only named textures which are used in GMod! For example, RadioButton is not listed here.

Unnamed Textures

This bug in only for layer 3.
Will be used shadow texture from last loaded skin! To fix it change SKIN in functions PaintShadow and PaintFrame to self.
List of unnamed layers
1 Texture of DProgress main body
2 Texture of DProgress progress body
3 Texture of DFrame outside shadow
4 Texture of selection for DTree and DIconBrowser
5 Texture of DTooltip <bug>DTooltip doesn't derive panel's skin. So it will be always "Default" skin. Works only when you set skin for it when it's visible.</bug>
6 Textures of default, hovered and pressed DSlider knob
7 Unused. Can be texture of vertical slider
8 Textures of default, hovered and pressed DNumberWang
9 Texture of DMenu check icon <note>DMenu doesn't derive panel's skin when called by DermaMenu. So it will be always "Default" skin. Works only when you set skin for it when it's visible or in DMenuBar.</note>
10 Textures of default, hovered and pressed DScrollPanel:GetVBar and DHorizontalDivider. Textures of default, hovered and pressed DComboBox button
11 Texture of selected DListView_Line
12 Texture of altered DListView_Line. To separate one line from another, DListView automatically color odd lines to slight dark color. Can be called by internal function DListView_Line:SetAltLine
13 Unused. Can be textures of alternative colors for DListView_Line
14 Texture of hovered DListView_Line
15 Unused
16 Texture of default DComboBox
17 Texture of hovered DComboBox
18 Texture of pressed DComboBox
19 Texture of disabled DComboBox
20 Texture of folded DCategoryList and DCollapsibleCategory
21 Texture of unfolded DCategoryList and DCollapsibleCategory
22 Texture of DCategoryList body
23 Unused
24 Textures of DFrame.btnClose button
25 Textures of DFrame.btnMinim button
26 Textures of DFrame.btnMaxim button
27 Unused. Can be textures of DFrame "Restore" button

Color Palette Texture

DermaSkin_Color_Numbered_Table_Updated.png
Color Palette Table
1 A No Color / Not Used
1 B Color of DFrame title when HasHierarchicalFocus is true
2 A No Color / Not Used
2 B Color of DFrame title when HasHierarchicalFocus is false
3 A Color of DButton text when IsDown is true
3 B Color of DButton default text
4 A Color of DButton text when IsEnabled is false
4 B Color of DButton text when IsHovered is true
5 A Color of DTab text when IsActive is true and IsDown is true
5 B Color of DTab default text when IsActive is true
6 A Color of DTab text when IsActive is true and IsEnabled is false
6 B Color of DTab text when IsActive is true and IsHovered is true
7 A Color of DTab text when IsActive is false and IsDown is true
7 B Color of DTab default text when IsActive is false
8 A Color of DTab text when IsActive is false and IsEnabled is false
8 B Color of DTab text when IsActive is false and IsHovered is true
9 A Color of DLabel and DListView_Line label when GetDark is true
9 B Color of DLabel and DListView_Line label when default
10 A Color of DLabel and DListView_Line label when GetHighlight is true
10 B Color of DLabel and DListView_Line label when GetBright is true
11 A Color of DTree_Node_Button text when IsHovered is true and DForm:ControlHelp text
11 B Color of DFileBrowser treeline
12 A Color of DTree_Node_Button text when IsSelected is true
12 B Color of DTree_Node_Button text when default
13 A Not Used. Colours.Properties.Line_Hover
13 B Not Used. Colours.Properties.Line_Normal
14 A Color of DProperties category label
14 B Not Used. Colours.Properties.Line_Selected
15 A Not Used. Colours.Properties.Column_Hover
15 B Not Used. Colours.Properties.Column_Normal
16 A Color of DProperties border between rows and columns
16 B Color of DProperties cell when row is being edited
17 A Not Used. Colours.Properties.Label_Hover
17 B Color of DProperties cell label when row isn't being edited
18 A No Color / Not Used
18 B Color of DProperties cell label when row is being edited
19 A Color of DCategoryHeader title when GetExpanded is false
19 B Not Used. Named as "ModalBackground"
20 A Color of DCategoryHeader title when GetExpanded is true
20 B Not Used. Named as "TooltipText" (Real tooltip text uses 27A)
21 A Color of DCollapsibleCategory:Add button text when not Atled and IsDown is true
21 B Color of DCollapsibleCategory:Add button text when not Atled
22 A Color of DCategoryList:AddItem element when Altered
22 B Color of DCollapsibleCategory:Add button text when not Atled and IsHovered is true
23 A Color of DCollapsibleCategory:Add button text when Atled
23 B Color of DCategoryList:AddItem element when Altered and IsHovered is true
24 A Color of DCollapsibleCategory:Add button text when Atled and IsHovered is true
24 B Color of DCategoryList:AddItem element when Altered and IsSelected is true
25 A Color of DCategoryList:AddItem element when IsHovered is true
25 B Color of DCollapsibleCategory:Add button text when not Atled and IsDown is true
26 A Color of DCategoryList:AddItem element when IsSelected is true
26 B Color of DCategoryList:AddItem element
27 A Color of DTooltip text. <bug>Currently broken.</bug>
27 B No Color / Not Used

Demo

For tutorial was created a Demo Addon with Windows 10 UI skin for Derma. You can download it here.

Addon uses this hook for painting all Derma objects:

hook.Add("ForceDermaSkin","Windows10SkinForce",function() return "Windows" -- This will paint all Derma objects to new skin end)