ProGUI V3 Alpha 3 Ready for testing!

Developed or developing a new product in PureBasic? Tell the world about it.
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

idle wrote: Fri Jan 24, 2025 2:18 am looking good. 8)
Thanks mate, it will look better - I did have border radius working the other day but I'm currently refactoring the code (with the base property, sub-property logic) - the skin colours are also horrible, purely for testing the transition animations with high contrast
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
User avatar
electrochrisso
Addict
Addict
Posts: 989
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by electrochrisso »

The transitions look nice and smooth. 8)
PureBasic! Purely the best 8)
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

electrochrisso wrote: Sun Jan 26, 2025 6:52 am The transitions look nice and smooth. 8)
Cheers mate! :) still refactoring the code, trying to simplify things as much as possible (general rule of thumb is if something is becoming too complex then it's time to refactor :wink: simplicity is king)
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

Hi guys!

So after 4 days of refactoring, the architecture is a lot simpler now and easier to understand and maintain. The new code can now handle missing state properties (so you no longer need to explicitly specify all the css for each state) you can just do a SkinSetValue("testContainer.testWidget", "active:border-radius", "20px") without needing pairing of the other states or specifying the base property (border).

Code: Select all

SkinSetValue("testContainer.testWidget", "background-color", "red")
SkinSetValue("testContainer.testWidget", "hover:background-color", "rgb(0, 255, 0)")
SkinSetValue("testContainer.testWidget", "border", "3px solid blue")
SkinSetValue("testContainer.testWidget", "hover:border-radius", "10px")
SkinSetValue("testContainer.testWidget", "active:border-radius", "20px")
SkinSetValue("testContainer.testWidget", "transition", "background-color 2s, border 1s, border-radius 1s")
The code now detects a base property such as "border" and any sub properties e.g. "border-radius", "border-xxx" with sub-properties sharing the base property memory. So now a single map lookup for WidgetGetSkinBorder(Widget, Property.s) instead of multiple map lookups inside that command for "border-radius", "border-top-left-radius" etc..

There's also a slight syntax change with a colon designating the state e.g SkinSetValue("testContainer.testWidget", "hover:border-radius", "20px"). Previously it was "hover.border-radius" however this was becoming difficult to parse with ambeguities such as "circle.background-color", "hover.circle.background-color" - is 'circle' a state? now "hover:circle.background-color". So that also matches web CSS syntax more closely too (for programmatically seting skin properties).

And now border-radius animation transitions are working! :) - this example also demonstrates 3 state transitions for the first time: normal, hover and active (so pretty much a button :lol: :wink:):

https://www.youtube.com/watch?v=K5oNEk_ipvI

What's nice is the 'background-color' of the red widgets only has a hover state of green yet animates correctly when the state gets set to 'active' (left mouse down).

Cheers!

Chris.
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

https://www.youtube.com/shorts/lPKJU4H3JSY

Hi guys!

Another major refactor of the core skin engine (third time lucky!), I was running into some issues with animation jumping (with different duration sub property transistions). There were also some issues with compositing a new state based on missing skin properties and how to build the new state in a cascading fashion.

A major under-the-hood refactor is the new internal command:

Code: Select all

registerSkinPropertyHandler(*parentProperty, Property.s, type.i, sizeOfData.i, *ParseFunction.skin_ValueParser, *AllocateFunction.skin_DataAllocateFunction, *CopyFunction.skin_DataCopyFunction, *FreeFunction.skin_DataFreeFunction, *TransitionFunction.skin_DataTransitionFunction = #Null, isParentTransition.b = #False)
So this allows a dynamic way to define skin property handlers of both base properties and sub-properties in a hierarchical way.

The current internal skin_Init() command currently looks like this:

Code: Select all

Procedure skin_Init()
    
    initColorNames()
    initTransitionFunctionNames()
    initBorderStyleNames()
    
    SkinMutex = CreateMutex()
    mutexName("SkinMutex") = SkinMutex
    
    registerSkinPropertyHandler(#Null, "transition", #PG_Skin_ValueType_Transition, SizeOf(SkinValueTransition), @skinParse_Transition(), @skinAllocate_Transition(), @skinCopy_Transition(), @skinFree_Transition())
    
    *border = registerSkinPropertyHandler(#Null, "border", #PG_Skin_ValueType_Border, SizeOf(SkinValueBorder), @skinParse_Border(), @skinAllocate_Border(), @skinCopy_Border(), @skinFree_Border())
    registerSkinPropertyHandler(*border, "border-style", #PG_Skin_ValueType_Border_Style, SizeOf(SkinValueBorder), @skinParse_Border_Style(), @skinAllocate_Border(), @skinCopy_Border_Style(), @skinFree_Border())
    *radius = registerSkinPropertyHandler(*border, "border-radius", #PG_Skin_ValueType_Border_Radius, SizeOf(SkinValueBorder), @skinParse_Border_Radius(), @skinAllocate_Border(), @skinCopy_Border_Radius(), @skinFree_Border())
    registerSkinPropertyHandler(*radius, "border-top-left-radius", #PG_Skin_ValueType_Border_Radius_TopLeft, SizeOf(SkinValueBorder), @skinParse_Border_Radius_TopLeft(), @skinAllocate_Border(), @skinCopy_Border_Radius_TopLeft(), @skinFree_Border(), @skinTransition_Border_Radius_TopLeft(), #True)
    registerSkinPropertyHandler(*radius, "border-top-right-radius", #PG_Skin_ValueType_Border_Radius_TopRight, SizeOf(SkinValueBorder), @skinParse_Border_Radius_TopRight(), @skinAllocate_Border(), @skinCopy_Border_Radius_TopRight(), @skinFree_Border(), @skinTransition_Border_Radius_TopRight(), #True)
    registerSkinPropertyHandler(*radius, "border-bottom-left-radius", #PG_Skin_ValueType_Border_Radius_BottomLeft, SizeOf(SkinValueBorder), @skinParse_Border_Radius_BottomLeft(), @skinAllocate_Border(), @skinCopy_Border_Radius_BottomLeft(), @skinFree_Border(), @skinTransition_Border_Radius_BottomLeft(), #True)
    registerSkinPropertyHandler(*radius, "border-bottom-right-radius", #PG_Skin_ValueType_Border_Radius_BottomRight, SizeOf(SkinValueBorder), @skinParse_Border_Radius_BottomRight(), @skinAllocate_Border(), @skinCopy_Border_Radius_BottomRight(), @skinFree_Border(), @skinTransition_Border_Radius_BottomRight(), #True)
    *color = registerSkinPropertyHandler(*border, "border-color", #PG_Skin_ValueType_Border_Color, SizeOf(SkinValueBorder), @skinParse_Border_Color(), @skinAllocate_Border(), @skinCopy_Border_Color(), @skinFree_Border(), #Null, #True)
    registerSkinPropertyHandler(*color, "border-top-color", #PG_Skin_ValueType_Border_Top_Color, SizeOf(SkinValueBorder), @skinParse_Border_Top_Color(), @skinAllocate_Border(), @skinCopy_Border_Top_Color(), @skinFree_Border(), @skinTransition_Border_Top_Color(), #True)
    registerSkinPropertyHandler(*color, "border-right-color", #PG_Skin_ValueType_Border_Right_Color, SizeOf(SkinValueBorder), @skinParse_Border_Right_Color(), @skinAllocate_Border(), @skinCopy_Border_Right_Color(), @skinFree_Border(), @skinTransition_Border_Right_Color(), #True)
    registerSkinPropertyHandler(*color, "border-bottom-color", #PG_Skin_ValueType_Border_Bottom_Color, SizeOf(SkinValueBorder), @skinParse_Border_Bottom_Color(), @skinAllocate_Border(), @skinCopy_Border_Bottom_Color(), @skinFree_Border(), @skinTransition_Border_Bottom_Color(), #True)
    registerSkinPropertyHandler(*color, "border-left-color", #PG_Skin_ValueType_Border_Left_Color, SizeOf(SkinValueBorder), @skinParse_Border_Left_Color(), @skinAllocate_Border(), @skinCopy_Border_Left_Color(), @skinFree_Border(), @skinTransition_Border_Left_Color(), #True)
    registerSkinPropertyHandler(*border, "border-top-width", #PG_Skin_ValueType_Border_Top_Width, SizeOf(SkinValueBorder), @skinParse_Border_Top_Width(), @skinAllocate_Border(), @skinCopy_Border_Top_Width(), @skinFree_Border(), @skinTransition_Border_Top_Width(), #True)
    registerSkinPropertyHandler(*border, "border-right-width", #PG_Skin_ValueType_Border_Right_Width, SizeOf(SkinValueBorder), @skinParse_Border_Right_Width(), @skinAllocate_Border(), @skinCopy_Border_Right_Width(), @skinFree_Border(), @skinTransition_Border_Right_Width(), #True)
    registerSkinPropertyHandler(*border, "border-bottom-width", #PG_Skin_ValueType_Border_Bottom_Width, SizeOf(SkinValueBorder), @skinParse_Border_Bottom_Width(), @skinAllocate_Border(), @skinCopy_Border_Bottom_Width(), @skinFree_Border(), @skinTransition_Border_Bottom_Width(), #True)
    registerSkinPropertyHandler(*border, "border-left-width", #PG_Skin_ValueType_Border_Left_Width, SizeOf(SkinValueBorder), @skinParse_Border_Left_Width(), @skinAllocate_Border(), @skinCopy_Border_Left_Width(), @skinFree_Border(), @skinTransition_Border_Left_Width(), #True)
    
    Global ProGUI_DefaultSkin
    
    ProGUI_DefaultSkin = CreateSkin("Default")
    
EndProcedure
So in the demo the CSS for that is (notice the different transition / animation durations for border-top-left-radius and border-bottom-right-radius):

Code: Select all

SkinSetValue("testContainer.testWidget", "background-color", "red")
SkinSetValue("testContainer.testWidget", "hover:background-color", "rgb(0, 255, 0)")
SkinSetValue("testContainer.testWidget", "border", "3px solid blue")
SkinSetValue("testContainer.testWidget", "border-left-width", "10px")
SkinSetValue("testContainer.testWidget", "border-color", "blue yellow")
SkinSetValue("testContainer.testWidget", "hover:border-radius", "10px")
SkinSetValue("testContainer.testWidget", "hover:border-top-left-radius", "40px 20px")
SkinSetValue("testContainer.testWidget", "hover:border-bottom-right-radius", "40px 20px")
SkinSetValue("testContainer.testWidget", "active:border", "20px double blue")
SkinSetValue("testContainer.testWidget", "active:border-top-left-radius", "40px 40px")
SkinSetValue("testContainer.testWidget", "active:border-color", "pink yellow purple red")

SkinSetValue("testContainer.testWidget", "transition", "background-color 2s, border 1s, border-radius 1s, border-top-left-radius 3s, border-bottom-right-radius 3s")
SkinSetValue("testContainer.testWidget", "hover:transition", "background-color .5s, border 1s ease-out-bounce, border-radius 1s ease-out-bounce")
Last edited by PrincieD on Tue Feb 04, 2025 2:26 am, edited 1 time in total.
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

So for "border-top-left-radius" the skin parse function looks like this:

Code: Select all

Procedure skinParse_Border_Radius_TopLeft(value.s, *data.SkinValueBorder)
    
    Protected.d rx, ry
    
    *data\tLeftRx = #Null
    *data\tLeftRy = #Null
    
    If parseBorderRadiusRxRy(value, @rx, @ry)
        
        *data\tLeftRx = rx
        *data\tLeftRy = ry
        
        ProcedureReturn #True
        
    EndIf
    
    ProcedureReturn #False
    
EndProcedure
The skin copy function:

Code: Select all

Procedure skinCopy_Border_Radius_TopLeft(*source.SkinValueBorder, *destination.SkinValueBorder)
    
    *destination\tLeftRx = *source\tLeftRx
    *destination\tLeftRy = *source\tLeftRy
    
EndProcedure
And the transition (animation) function looks like this:

Code: Select all

Procedure skinTransition_Border_Radius_TopLeft(*transition, *start.SkinValueBorder, *end.SkinValueBorder, *current.SkinValueBorder)
    
    *current\tLeftRx = transition_Function(*transition, *start\tLeftRx, *end\tLeftRx)
    *current\tLeftRy = transition_Function(*transition, *start\tLeftRy, *end\tLeftRy)

EndProcedure
And for the WidgetGetSkinBorder(Widget, Property.s) function:

Code: Select all

ProcedureDLL WidgetGetSkinBorder(Widget, Property.s)
    
    If Not Widget Or Property = ""
        
        ProcedureReturn #False
        
    EndIf
    
    If WidgetGetSkinData(Widget, Property, @*border.SkinValueBorder, @valueType) And valueType = #PG_Skin_ValueType_Border
        
        If Not *border\border
            *border\border = CreateBorder()
        EndIf
        
        ;If Not *border\style
        ;    ProcedureReturn #Null
        ;EndIf
        
        BorderSetFlags(*border\border, *border\style)
        BorderSetWidth(*border\border, *border\lwidth, *border\twidth, *border\rwidth, *border\bwidth)
        BorderSetColor(*border\border, *border\lColor, *border\lOpacity, *border\tColor, *border\tOpacity, *border\rColor, *border\rOpacity, *border\bColor, *border\bOpacity)
        BorderSetRadius(*border\border, *border\tLeftRx, *border\tLeftRy, *border\tRightRx, *border\tRightRy, *border\bLeftRx, *border\bLeftRy, *border\bRightRx, *border\bRightRy)
        
        ProcedureReturn *border\border
        
    EndIf
    
    ProcedureReturn #False
    
EndProcedure
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

Another slight refactor of the skin engine internals:

Previously:

Code: Select all

registerSkinPropertyHandler(#Null, "transition", #PG_Skin_ValueType_Transition, SizeOf(SkinValueTransition), @skinParse_Transition(), @skinAllocate_Transition(), @skinCopy_Transition(), @skinFree_Transition())
    
    *border = registerSkinPropertyHandler(#Null, "border", #PG_Skin_ValueType_Border, SizeOf(SkinValueBorder), @skinParse_Border(), @skinAllocate_Border(), @skinCopy_Border(), @skinFree_Border())
    registerSkinPropertyHandler(*border, "border-style", #PG_Skin_ValueType_Border_Style, SizeOf(SkinValueBorder), @skinParse_Border_Style(), @skinAllocate_Border(), @skinCopy_Border_Style(), @skinFree_Border())
    *radius = registerSkinPropertyHandler(*border, "border-radius", #PG_Skin_ValueType_Border_Radius, SizeOf(SkinValueBorder), @skinParse_Border_Radius(), @skinAllocate_Border(), @skinCopy_Border_Radius(), @skinFree_Border())
    registerSkinPropertyHandler(*radius, "border-top-left-radius", #PG_Skin_ValueType_Border_Radius_TopLeft, SizeOf(SkinValueBorder), @skinParse_Border_Radius_TopLeft(), @skinAllocate_Border(), @skinCopy_Border_Radius_TopLeft(), @skinFree_Border(), @skinTransition_Border_Radius_TopLeft(), #True)
    registerSkinPropertyHandler(*radius, "border-top-right-radius", #PG_Skin_ValueType_Border_Radius_TopRight, SizeOf(SkinValueBorder), @skinParse_Border_Radius_TopRight(), @skinAllocate_Border(), @skinCopy_Border_Radius_TopRight(), @skinFree_Border(), @skinTransition_Border_Radius_TopRight(), #True)
    registerSkinPropertyHandler(*radius, "border-bottom-left-radius", #PG_Skin_ValueType_Border_Radius_BottomLeft, SizeOf(SkinValueBorder), @skinParse_Border_Radius_BottomLeft(), @skinAllocate_Border(), @skinCopy_Border_Radius_BottomLeft(), @skinFree_Border(), @skinTransition_Border_Radius_BottomLeft(), #True)
    registerSkinPropertyHandler(*radius, "border-bottom-right-radius", #PG_Skin_ValueType_Border_Radius_BottomRight, SizeOf(SkinValueBorder), @skinParse_Border_Radius_BottomRight(), @skinAllocate_Border(), @skinCopy_Border_Radius_BottomRight(), @skinFree_Border(), @skinTransition_Border_Radius_BottomRight(), #True)
    *color = registerSkinPropertyHandler(*border, "border-color", #PG_Skin_ValueType_Border_Color, SizeOf(SkinValueBorder), @skinParse_Border_Color(), @skinAllocate_Border(), @skinCopy_Border_Color(), @skinFree_Border(), #Null, #True)
    registerSkinPropertyHandler(*color, "border-top-color", #PG_Skin_ValueType_Border_Top_Color, SizeOf(SkinValueBorder), @skinParse_Border_Top_Color(), @skinAllocate_Border(), @skinCopy_Border_Top_Color(), @skinFree_Border(), @skinTransition_Border_Top_Color(), #True)
    registerSkinPropertyHandler(*color, "border-right-color", #PG_Skin_ValueType_Border_Right_Color, SizeOf(SkinValueBorder), @skinParse_Border_Right_Color(), @skinAllocate_Border(), @skinCopy_Border_Right_Color(), @skinFree_Border(), @skinTransition_Border_Right_Color(), #True)
    registerSkinPropertyHandler(*color, "border-bottom-color", #PG_Skin_ValueType_Border_Bottom_Color, SizeOf(SkinValueBorder), @skinParse_Border_Bottom_Color(), @skinAllocate_Border(), @skinCopy_Border_Bottom_Color(), @skinFree_Border(), @skinTransition_Border_Bottom_Color(), #True)
    registerSkinPropertyHandler(*color, "border-left-color", #PG_Skin_ValueType_Border_Left_Color, SizeOf(SkinValueBorder), @skinParse_Border_Left_Color(), @skinAllocate_Border(), @skinCopy_Border_Left_Color(), @skinFree_Border(), @skinTransition_Border_Left_Color(), #True)
    registerSkinPropertyHandler(*border, "border-top-width", #PG_Skin_ValueType_Border_Top_Width, SizeOf(SkinValueBorder), @skinParse_Border_Top_Width(), @skinAllocate_Border(), @skinCopy_Border_Top_Width(), @skinFree_Border(), @skinTransition_Border_Top_Width(), #True)
    registerSkinPropertyHandler(*border, "border-right-width", #PG_Skin_ValueType_Border_Right_Width, SizeOf(SkinValueBorder), @skinParse_Border_Right_Width(), @skinAllocate_Border(), @skinCopy_Border_Right_Width(), @skinFree_Border(), @skinTransition_Border_Right_Width(), #True)
    registerSkinPropertyHandler(*border, "border-bottom-width", #PG_Skin_ValueType_Border_Bottom_Width, SizeOf(SkinValueBorder), @skinParse_Border_Bottom_Width(), @skinAllocate_Border(), @skinCopy_Border_Bottom_Width(), @skinFree_Border(), @skinTransition_Border_Bottom_Width(), #True)
    registerSkinPropertyHandler(*border, "border-left-width", #PG_Skin_ValueType_Border_Left_Width, SizeOf(SkinValueBorder), @skinParse_Border_Left_Width(), @skinAllocate_Border(), @skinCopy_Border_Left_Width(), @skinFree_Border(), @skinTransition_Border_Left_Width(), #True)
Currently:

Code: Select all

registerSkinProperty("transition", #PG_Skin_Type_Transition, SizeOf(SkinValueTransition), @skinParse_Transition(), @skinAllocate_Transition(), @skinCopy_Transition(), @skinFree_Transition())
    
    *border = registerSkinProperty("border", #PG_Skin_Type_Border, SizeOf(SkinValueBorder), @skinParse_Border(), @skinAllocate_Border(), @skinCopy_Border(), @skinFree_Border())
    registerSkinSubProperty(*border, "border-style", 1, @skinParse_Border_Style(), @skinCopy_Border_Style())
    registerSkinSubProperty(*border, "border-top-style", 2, @skinParse_Border_Top_Style(), @skinCopy_Border_Style())
    registerSkinSubProperty(*border, "border-right-style", 2, @skinParse_Border_Right_Style(), @skinCopy_Border_Style())
    registerSkinSubProperty(*border, "border-bottom-style", 2, @skinParse_Border_Bottom_Style(), @skinCopy_Border_Style())
    registerSkinSubProperty(*border, "border-left-style", 2, @skinParse_Border_Left_Style(), @skinCopy_Border_Style())
    registerSkinSubProperty(*border, "border-radius", 1, @skinParse_Border_Radius(), @skinCopy_Border_Radius())
    registerSkinSubProperty(*border, "border-top-left-radius", 2, @skinParse_Border_Radius_TopLeft(), @skinCopy_Border_Radius_TopLeft(), @skinTransition_Border_Radius_TopLeft(), "border-radius")
    registerSkinSubProperty(*border, "border-top-right-radius", 2, @skinParse_Border_Radius_TopRight(), @skinCopy_Border_Radius_TopRight(), @skinTransition_Border_Radius_TopRight(), "border-radius")
    registerSkinSubProperty(*border, "border-bottom-left-radius", 2, @skinParse_Border_Radius_BottomLeft(), @skinCopy_Border_Radius_BottomLeft(), @skinTransition_Border_Radius_BottomLeft(), "border-radius")
    registerSkinSubProperty(*border, "border-bottom-right-radius", 2, @skinParse_Border_Radius_BottomRight(), @skinCopy_Border_Radius_BottomRight(), @skinTransition_Border_Radius_BottomRight(), "border-radius")
    registerSkinSubProperty(*border, "border-color", 1, @skinParse_Border_Color(), @skinCopy_Border_Color())
    registerSkinSubProperty(*border, "border-top", 2, @skinParse_Border_Top(), @skinCopy_Border_Top())
    registerSkinSubProperty(*border, "border-top-color", 3, @skinParse_Border_Top_Color(), @skinCopy_Border_Top_Color(), @skinTransition_Border_Top_Color(), "border-top, border-color, border")
    registerSkinSubProperty(*border, "border-right-color", 3, @skinParse_Border_Right_Color(), @skinCopy_Border_Right_Color(), @skinTransition_Border_Right_Color(), "border-right, border-color, border")
    registerSkinSubProperty(*border, "border-bottom-color", 3, @skinParse_Border_Bottom_Color(), @skinCopy_Border_Bottom_Color(), @skinTransition_Border_Bottom_Color(), "border-bottom, border-color, border")
    registerSkinSubProperty(*border, "border-left-color", 3, @skinParse_Border_Left_Color(), @skinCopy_Border_Left_Color(), @skinTransition_Border_Left_Color(), "border-left, border-color, border")
    registerSkinSubProperty(*border, "border-top-width", 3, @skinParse_Border_Top_Width(), @skinCopy_Border_Top_Width(), @skinTransition_Border_Top_Width(), "border-top, border-width, border")
    registerSkinSubProperty(*border, "border-right-width", 3, @skinParse_Border_Right_Width(), @skinCopy_Border_Right_Width(), @skinTransition_Border_Right_Width(), "border-right, border-width, border")
    registerSkinSubProperty(*border, "border-bottom-width", 3, @skinParse_Border_Bottom_Width(), @skinCopy_Border_Bottom_Width(), @skinTransition_Border_Bottom_Width(), "border-bottom, border-width, border")
    registerSkinSubProperty(*border, "border-left-width", 3, @skinParse_Border_Left_Width(), @skinCopy_Border_Left_Width(), @skinTransition_Border_Left_Width(), "border-left, border-width, border")
There were some issues with the previous parent / child hierarchy of the property handlers and how CSS works. It mostly worked but then ran into issues with properties like 'border-top', 'border-color'. 'border-top-color' can be a child of 'border-top' but 'border-top' can't be a child of 'border-color' (because 'border-top' sets the top border style, color and width). So now the new registerSkinSubProperty() command has a cascade order parameter and if it has a transition function defined there is an optional transitionOrder string parameter that is a comma separated list of fall-back transition parameters that can animate it. For example:

Code: Select all

registerSkinSubProperty(*border, "border-top-width", 3, @skinParse_Border_Top_Width(), @skinCopy_Border_Top_Width(), @skinTransition_Border_Top_Width(), "border-top, border-width, border")
First 'border-top-width' is checked in the transition property (SkinSetValue("testContainer.testWidget", "transition", "background-color 2s, border 1s, border-radius 1s, border-top-left-radius 3s, border-bottom-right-radius 3s")) then 'border-top', 'border-width' and 'border'.

You shouldn't have to worry about this at all but I will be opening up these commands down the line for advanced usage (you need custom skin property handlers for some reason).
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

I don't think I've shared this before but this is currently the source code include path for ProGUI V3:

Code: Select all

ProGUI_Animation.pbi
ProGUI_Core.pbi
ProGUI_Events.pbi
ProGUI_GFX.pbi
ProGUI_GFX_Cairo.pbi
ProGUI_GFX_Direct2D.pbi
ProGUI_GFX_Drivers.pbi
ProGUI_Layout.pbi
ProGUI_OS.pbi
ProGUI_OS_Linux.pbi
ProGUI_OS_Windows.pbi
ProGUI_OS_Windows_Capture.pbi
ProGUI_OS_Windows_Core.pbi
ProGUI_OS_Windows_Diverted.pbi
ProGUI_OS_Windows_ScrollBar.pbi
ProGUI_OS_Windows_Webview.pbi
ProGUI_Skin.pbi
ProGUI_Widget.pbi
ProGUI_Widget_ScrollBar.pbi
ProGUI_Widget_Webview.pbi
ProGUI_Window.pbi
ProGUI.pbi
So slightly better than the ProGUI V1.xx monolith :lol:
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

Hi guys, the skin engine is progressing nicely. Border CSS is complete (and is exactly the same as web CSS). The first proper widget to use the skin engine is now the scrollbar widget (with class "scrollbar") which all layouts use. The scrollbar widget is now almost indistinguishable from the native OS Windows 10 scrollbar with animation transitions (except better consistent animation with a solid framerate, each native win32 control seems to have a slightly different implementation with animation tied to the main window message pump events - so framerate janky at times). So currently the default Windows 10 skin for scrollbars currently looks like this (default light theme):

Code: Select all

SkinSetValue("scrollbar", "", "", "background-color", "#F0F0F0")
SkinSetValue("scrollbar", "", "thumb1", "background-color", "#F0F0F0")
SkinSetValue("scrollbar", "", "thumb2", "background-color", "#F0F0F0")
SkinSetValue("scrollbar", "", "trackbar", "background-color", "#CDCDCD")
SkinSetValue("scrollbar", "hover", "thumb1", "background-color", "#DADADA")
SkinSetValue("scrollbar", "hover", "thumb2", "background-color", "#DADADA")
SkinSetValue("scrollbar", "hover", "trackbar", "background-color", "#A6A6A6")
SkinSetValue("scrollbar", "active", "thumb1", "background-color", "#606060")
SkinSetValue("scrollbar", "active", "thumb2", "background-color", "#606060")
SkinSetValue("scrollbar", "active", "trackbar", "background-color", "#606060")
SkinSetValue("scrollbar", "", "trackbar", "transition", "background-color 1s")
SkinSetValue("scrollbar", "hover", "trackbar", "transition", "background-color .3s")
SkinSetValue("scrollbar", "active", "trackbar", "transition", "background-color 0s")
SkinSetValue("scrollbar", "", "thumb1", "transition", "background-color 1s")
SkinSetValue("scrollbar", "hover", "thumb1", "transition", "background-color .3s")
SkinSetValue("scrollbar", "active", "thumb1", "transition", "background-color 0s")
SkinSetValue("scrollbar", "", "thumb2", "transition", "background-color 1s")
SkinSetValue("scrollbar", "hover", "thumb2", "transition", "background-color .3s")
SkinSetValue("scrollbar", "active", "thumb2", "transition", "background-color 0s")
I've made the SkinSetValue() command more explicit (slightly more verbose) as it will only be used really for dynamically changing skin property values (most of the time you will edit the skin CSS file directly) - this also allows string constants to be used instead of having to remember a markup language (which could change) so: SkinSetValue(ClassPath.s, State.s, Component.s, Property.s, Value.s, Skin = #Null)
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

Skin background images are coming along nicely! :D

https://www.youtube.com/shorts/aH8t5tpPQz0

The syntax is the same as Web CSS and you can have as many 'layers' as you want:

Code: Select all

SkinSetValue("testWidget3", "", "", "background-image", "url('icons/boingball.png'), url('icons/boingball2.png'), url('icons/background1.png')")
SkinSetValue("testWidget3", "", "", "background-position-x", "20px, 30px, 0px")
SkinSetValue("testWidget3", "hover", "", "background-position-x", "60px, 0px, -130px")
SkinSetValue("testWidget3", "", "", "transition", "background-position-x 1s")
I'll be adding a new none-standard CSS "background-opacity" property too (that's animatiable) so cross-fading should be easy (Web CSS doesn't support this surprisingly).

The draw event handler for the widget looks like this:

Code: Select all

Procedure drawTestWidget(Widget, EventType, *eventData.PG_EventDraw)
    
    DrawSkinBackground(Widget, "", 0, 0, *eventData\width, *eventData\height)
    
EndProcedure
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

Background opacity is now working :)

https://www.youtube.com/shorts/j__E1TUgmS0

Surprisingly the Web CSS specification doesn't support individual background opacity so this is an upgrade to standard CSS with the addition of a new 'background-opacity' property.

To do this in HTML and CSS you would need 4 Divs overlaid on top of each other and would have to alter the opacity of each Div (through JS probably).

So the CSS for the widget looks like this:

Code: Select all

SkinSetValue("testWidget3", "", "", "background-image", "url('icons/boingball.png'), url('icons/dccmanager/movie8_128x128.png'), url('icons/boingball2.png'), url('icons/background1.png')")
SkinSetValue("testWidget3", "", "", "background-position-x", "20px, 20px, 30px, 0px")
SkinSetValue("testWidget3", "hover", "", "background-position-x", "60px, 60px, 0px, -130px")
SkinSetValue("testWidget3", "", "", "background-opacity", "100%, 0%, 100%, 100%")
SkinSetValue("testWidget3", "hover", "", "background-opacity", "0%, 100%, 50%, 100%")
SkinSetValue("testWidget3", "active", "", "background-opacity", "0%, 100%, 0%, 0%")
SkinSetValue("testWidget3", "", "", "transition", "background-position-x 1s, background-opacity 1s")
P.s I turned 43 today, old bastard now :lol:
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

https://www.youtube.com/shorts/kyvbpNEkozM

There was a slight animation pause in the previous example when transitioning midway from a hover state to active due to CRC32 checksums not being calculated correctly for the new skin properties that can have a 'list' of elements. The checksums are used when animating between states and let the animation system know whether the new skin state is the same as the previous and if so let the previous animation continue (if already animating). Ping-ponging is working correctly again now too, so when a transition is animating between 2 states and the states are flipped midway e.g. normal and hover when the mouse moves away and back again quickly.
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
User avatar
idle
Always Here
Always Here
Posts: 5834
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by idle »

PrincieD wrote: Mon Feb 17, 2025 11:13 pm P.s I turned 43 today, old bastard now :lol:
happy birthday, I stick with 42, it has a nice ring to it! No need for Deep Thought on that one. 101010
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

idle wrote: Wed Feb 19, 2025 1:44 am
PrincieD wrote: Mon Feb 17, 2025 11:13 pm P.s I turned 43 today, old bastard now :lol:
happy birthday, I stick with 42, it has a nice ring to it! No need for Deep Thought on that one. 101010
Thanks mate haha I'm 38 if any ladies are asking :lol:
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
PrincieD
Addict
Addict
Posts: 858
Joined: Wed Aug 10, 2005 2:08 pm
Location: Yorkshire, England
Contact:

Re: ProGUI V3 Alpha 3 Ready for testing!

Post by PrincieD »

So for that demo, the mouse event handler looks like this:

Code: Select all

Procedure testWidgetMouse(Widget, EventType, *eventData.PG_EventMouse)
    
    Select EventType
            
        Case #PG_Event_MouseLeftButtonDown, #PG_Event_MouseLeftDoubleClick
            
            WidgetSetSkinState(Widget, "active")
            
        Case #PG_Event_MouseLeftButtonUp
            
            WidgetSetSkinState(Widget, "hover")
            WidgetSetSkinState(Widget, "hover", "circle")
            
        Case #PG_Event_MouseEnter
            
            WidgetSetSkinState(Widget, "hover")
            WidgetSetSkinState(Widget, "hover", "circle")
            
        Case #PG_Event_MouseLeave
            
            WidgetSetSkinState(Widget, "")
            WidgetSetSkinState(Widget, "", "circle")
            
    EndSelect
    
EndProcedure
"circle" is testing out sub elements / components for example the scrollbar widget currently has "thumb1", "thumb2" and "trackbar" component / elements
ProGUI - Professional Graphical User Interface Library - http://www.progui.co.uk
Post Reply