Sign in to follow this  
Followers 0
JRowe

Advanced GUI UDF design

10 posts in this topic

I know it's reinventing the wheel, in one sense, but I've just hacked through the PNG as GUI code, and discovered that I could place large(unlimited?) numbers of windows containing semi-transparent png images as children of the parent GUI, that animate smoothly, without flicker,through both fading and moving, and register their events cleanly (i.e.mouse-over, click, drag, etc.)

I have the basic idea for a message handler, but I'd like to reuse windows messages wherever possible, such as in the case of the $WM_NCHITTEST included in the PNG as GUI setup, which allowed dragging of the background image.

I'llpost a demo tomorrow, after I clean things up a bit (I'm using pngsfrom all over my computer). Basically, the setup goes like this:

Create a GUI with _GUICreate_Alpha, thanks to Kip.

Func _GUICreate_Alpha($sTitle, $sPath, $iX=-1, $iY=-1, $iOpacity=255)
    Local $hGUI, $hImage, $hScrDC, $hMemDC, $hBitmap, $hOld, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend
    $hImage = _GDIPlus_ImageLoadFromFile($sPath)
    $width = _GDIPlus_ImageGetWidth($hImage)
    $height = _GDIPlus_ImageGetHeight($hImage)
    $hGUI = GUICreate($sTitle, $width, $height, $iX, $iY, $WS_POPUP, $WS_EX_LAYERED)
    $hScrDC = _WinAPI_GetDC(0)
    $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC)
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $hOld = _WinAPI_SelectObject($hMemDC, $hBitmap)
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", $width)
    DllStructSetData($tSize, "Y", $height)
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", 1)
    _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, 2)
    _WinAPI_ReleaseDC(0, $hScrDC)
    _WinAPI_SelectObject($hMemDC, $hOld)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteObject($hImage)
    _WinAPI_DeleteDC($hMemDC)
EndFunc

Create a control container GUI, that contains normal windows controls, like inputs, edits, buttons, and so on.

$controlGui= GUICreate("ControlGUI", 800, 600, 0, 0, $WS_POPUP,BitOR($WS_EX_LAYERED, $WS_EX_MDICHILD), WinGetHandle("My PNG GUI"))
GUICtrlCreatePic(@ScriptDir & "\appIcons\grey.gif", 0, 0, 800, 600)
GUICtrlSetState(-1, $GUI_DISABLE)



$button1 = GuiCtrlCreateButton("test",100,100, 68,22)

Create each individual additional GUI widget as a child of the "My PNG GUI" using the SetBitMap() function from lod3n.

Func SetBitmap($hGUI, $hImage, $iOpacity)
    Local $hScrDC, $hMemDC, $hBitmap, $hOld, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend

    $hScrDC = _WinAPI_GetDC(0)
    $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC)
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $hOld = _WinAPI_SelectObject($hMemDC, $hBitmap)
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", _GDIPlus_ImageGetWidth($hImage))
    DllStructSetData($tSize, "Y", _GDIPlus_ImageGetHeight($hImage))
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", $AC_SRC_ALPHA)
    _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA)
    _WinAPI_ReleaseDC(0, $hScrDC)
    _WinAPI_SelectObject($hMemDC, $hOld)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hMemDC)
EndFunc

I'dlike to UDF-ize this idea, and create advanced GUI widgets like Accordions, Carousels, and so on.

Are there any resources or guidelines in designing something like this? I'd like to keep it to as little overhead as possible, and reuseexisting Windows functionality.

So, I thought I'd post the idea here to see if I could interest any others in the idea. I'd love the assistance of a pro or two.

I think it looks cool, and could lead to some great eye candy.

It was a pain in the arse to get the PNGs to behave correctly. I kid you not.

Major kudos to PaulIA, who made this stuff possible.

Share this post


Link to post
Share on other sites



hi JRowe

I'd like to help, but I'm afraid I can't

But you can count with my vote. Please, keep on!

alc

Share this post


Link to post
Share on other sites

Very Interesting!!

I converted one of my jpg photos to png and replaced it in your script.

It works very well. Since these are buttons I guess you could click them and run a script.

Lots of neat possibilities.

Good work.

REB


MEASURE TWICE - CUT ONCE

Share this post


Link to post
Share on other sites

They aren't buttons, actually, they're individual windows, children of the parent image. However, they can be used as buttons by intercepting the button related interactions with the GUI (mousedown, mouseup.) I'm looking at the rotation and other animations people have done using the GDIPlus functions. There's a whole lot of stuff out there that's never been consolidated. This should be a lot of fun. :D

Share this post


Link to post
Share on other sites

My mistake.

Thanks for the info on how to use them as buttons.

It will be interesting to see how far this will go when

everybody gets a look at your work.

Should be lots of action then.

REB


MEASURE TWICE - CUT ONCE

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

So I'm trying to come up with every conceivable basic element that is needed for more advanced functions. I have parenting, z order, dimensions, placement, styling, behaviors, user functions, event tracking, animations, animation target, transition type, and skinning. Animations happen outside of drawing. For example, a resize event would re-draw the GUI in the appropriate location. An animation event doesn't necessarily redraw the element, but can use the existing image and modify its location, orientation, or size.

;String Name of Widget. Error thrown if Duplicate name tried
$GUIArray[$n][0] = $Name
;Skin Name
$GUIArray[$n][1] = $Skin
;Int
$GUIArray[$n][2] = $X
;Int
$GUIArray[$n][3] = $Y
;Int
$GUIArray[$n][4] = $Width
;Int
$GUIArray[$n][5] = $Height
;Relative z order, changes depending on parent object.
$GUIArray[$n][6] = $ZOrder
;User Specified Data, handled in the $Notification function
$GUIArray[$n][7] = $Data
;$GUIArray Index of Parent Element
$GUIArray[$n][8] = $Parent
;Hardcoded "Type" of Widget
$GUIArray[$n][9] = $Type
;0,1,2,4,8,16,32 and so on, binary delimited styles, using BitOr($PNGGUIModal) style, etc
$GUIArray[$n][10] = $Styles
;Set by the main GUI loop on any event
$GUIArray[$n][11] = $CurrentEvent
;Widget Function Name, can be redirected, disabled, etc - ButtonFnc for buttons, LabelFnc for labels, etc
$GUIArray[$n][12] = $Notification
;Denotes type of Animation being performed. Fade, Translate, Rotate, Scale, Crop, etc.
$GUIArray[$n][13] = $Animation
;Denotes Transition type
$GUIArray[$n][14] = $Transition
;Denotes Current Animation target. Target depends onnimationType
$GUIArray[$n][15] = $AnimationTarget
;Widget dependent flag denoting state of widget
$GUIArray[$n][16] = $WidgetState

The user will create a button like so:

_PNGGUIButtonCreate($sMyButtonName, $x, $y, "Button Title", "myButtonFunction", $width=100, $height=25, $skin = "currentSkin", $Styles = "default")

This would return the unique name of the button (if the $sMyButtonName string isn't unique, an error is thrown.)

The user will only have to specify a name, a place, a title, and a function. The rest would be handled by the skin or the default parameters of the widget, or both.

PNG GUI System:

$myButton = _PNGGUIButtonCreate($sName, $x, $y, $Title,  $Function)

AutoIt GUI System:

$myButton = GUICtrlCreateButton($sTitle, $x, $y)

The PNG GUI system has two additional parameters for a plain vanilla widget, but when you take into consideration the attendant event handling required to fire an event for the default GUI system, the two are about equally easy to use.

Animations will be a parameter used in the widget function. A widget can have different animation targets that respond to different events (color changes, fading,moving, and so on.) Animations will be time based, so that each loop of the GUI process will update the screen, so that animation speed will be independent of the system it's run on, and animations won't block the process. Transitions will allow different effects to be used, based on performance and visual expectations of the widget designer. Complex GUI interactions, such as the animation of an Accordion control, or a Sliding Menu Ribbon, or even an iTunes coverFlow control, can be easily defined, designed, and implemented with this specification of elements.

I think I've covered all the bases, and I'll begin programming this system tomorrow afternoon.

Please comment if you have any ideas, critiques, or insights, I truly appreciate any discussion. I especially want to know if anyone sees problems or redundancy that can be taken out of the system.

Thanks!

Edited by JRowe

Share this post


Link to post
Share on other sites

This is a truly unique and amibitious project. I can't wait to see what you come up with. What you have so far sounds really well thought out and comprehensive. I don't think I have anything to add at the moment, maybe when we start to see some of it in action. I'd like to offer my assistance if you need some help. GDI+ isn't my strong suit, but I'll help with what I can.

Share this post


Link to post
Share on other sites

I did some monkeying around trying to make the moon go around the earth. I'm most of the way there but couldn't figure out a way to put the child gui behind the primary gui. I suspect there is a way but couldn't figure it out.

Anyways here is the code. It might help in your endeavour.

#include <GDIPlus.au3>
#include <WindowsConstants.au3>
#include <GuiConstantsEx.au3>
#include <StaticConstants.au3>
Global Const $AC_SRC_ALPHA = 1
Global $GuiSize = 100, $hScrDC, $hMemDC, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend
Global $t1, $iX1 = 100, $iY1 = 100, $tPoint, $pPoint, $Speed = 3, $iValX = $Speed, $iValY = $Speed
_GDIPlus_Startup()

$pngSrc = @ScriptDir & "\earth.png"
   ; Load Image
    $oldImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\moon.png")
    ;ToolTip(_GDIPlus_ImageGetWidth($oldImage)&" x "&_GDIPlus_ImageGetHeight($oldImage))

;This allows the png to be dragged by clicking anywhere on the main image.
GUIRegisterMsg($WM_NCHITTEST, "WM_NCHITTEST")
$GUI = _GUICreate_Alpha("Look at the shiny", $pngSrc)
$myGuiHandle = WinGetHandle("Look at the shiny")
GUISetState()

;This is an invisible control container. You can create regular windows controls on this panel.
$controlGui = GUICreate("ControlGUI", 800, 800, 0, 0, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_MDICHILD), $myGuiHandle)
GUICtrlSetBkColor($controlGui, 0xFF00FF)
GUICtrlSetState(-1, $GUI_DISABLE)


;This png is draggable as if it were a child window. It has about 50 pixels at the top that allow it to be dragged
$TransparentButtonTest = GUICreate("Test321", 300, 300, 350, 350, $WS_EX_MDICHILD, $WS_EX_LAYERED, $myGuiHandle)
SetBitMap($TransparentButtonTest, $oldImage, 255)

GUISetState()

$iX1=350
$iY1=350
$iW=200
$iH=200
$direction=1
$size=1
While 1

    $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
            ExitLoop

    EndSelect
sleep(30)
WinMove($TransparentButtonTest,"",$iX1,$iY1)
;        DllStructSetData($tPoint, "X", $iX1) ; Update point destination dll data structure X value.
 ;      DllStructSetData($tPoint, "Y", $iY1) ; Update point destination dll data structure Y value.
;       _WinAPI_UpdateLayeredWindow($TransparentButtonTest, $hScrDC, $pPoint, $pSize, $hMemDC, $pSource, 0, $pBlend, $AC_SRC_ALPHA)
$hImage1=_ImageResize($iW,$iH)
SetBitMap($TransparentButtonTest, $hImage1, 255)
$iX1=$iX1+(3*$direction)
$iY1=$iY1+(1*$direction)
if $direction=1 Then
    $iW=$iW+(1*$size)
    $iH=$iH+(1*$size)

EndIf

    If $iX1>325 and $iX1<375 and $size=1 Then
        $size=-1
    elseIf $iX1>600 and $size=-1 Then
        $direction=-1
        $size=1
    elseIf $iX1<100 and $size=-1 Then
        $direction=1
        $size=1
    EndIf

WEnd
_GDIPlus_ImageDispose($oldImage)
_GDIPlus_Shutdown()

Func WM_NCHITTEST($hWnd, $iMsg, $iwParam, $ilParam)
    If ($hwnd = WinGetHandle("Look at the shiny")) And ($iMsg = $WM_NCHITTEST) Then
    Return $HTCAPTION
    EndIf
EndFunc

Func _GUICreate_Alpha($sTitle, $sPath, $iX=-1, $iY=-1, $iOpacity=255)
    Local $hGUI, $hImage, $hScrDC, $hMemDC, $hBitmap, $hOld, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend
    $hImage = _GDIPlus_ImageLoadFromFile($sPath)
    $width = _GDIPlus_ImageGetWidth($hImage)
    $height = _GDIPlus_ImageGetHeight($hImage)
    $hGUI = GUICreate($sTitle, $width, $height, $iX, $iY, $WS_POPUP, $WS_EX_LAYERED)
    $hScrDC = _WinAPI_GetDC(0)
    $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC)
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $hOld = _WinAPI_SelectObject($hMemDC, $hBitmap)
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", $width)
    DllStructSetData($tSize, "Y", $height)
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", 1)
    _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, 2)
    _WinAPI_ReleaseDC(0, $hScrDC)
    _WinAPI_SelectObject($hMemDC, $hOld)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteObject($hImage)
    _WinAPI_DeleteDC($hMemDC)
EndFunc ;==>_GUICreate_Alpha

Func SetBitmap($hGUI, $hImage, $iOpacity)
    Local $hScrDC, $hMemDC, $hBitmap, $hOld, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend
    
    $hScrDC = _WinAPI_GetDC(0)
    $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC)
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $hOld = _WinAPI_SelectObject($hMemDC, $hBitmap)
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", _GDIPlus_ImageGetWidth($hImage))
    DllStructSetData($tSize, "Y", _GDIPlus_ImageGetHeight($hImage))
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    $tPoint = DllStructCreate($tagPOINT) ; Create point destination structure here
    $pPoint = DllStructGetPtr($tPoint) ; Create pointer to this dll data structure, $pPTDest parameter
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", $AC_SRC_ALPHA)
    _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA)
    _WinAPI_ReleaseDC(0, $hScrDC)
    _WinAPI_SelectObject($hMemDC, $hOld)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hMemDC)
EndFunc   ;==>SetBitmap


Func _ImageDrawText($hImage, $sText, $iX = 0, $iY = 0, $iRGB = 0x000000, $iSize = 9, $iStyle = 0, $sFont = "Arial") 
    Local $w, $h, $hGraphic1, $hBitmap, $hGraphic2, $hBrush, $hFormat, $hFamily, $hFont, $tLayout, $aInfo
    $w = _GDIPlus_ImageGetWidth($hImage)
    $h = _GDIPlus_ImageGetHeight($hImage)
    
    ;Create a new bitmap, this way the original opened png is left unchanged
    $hGraphic1 = _GDIPlus_GraphicsCreateFromHWND(_WinAPI_GetDesktopWindow())
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($w, $h, $hGraphic1)
    $hGraphic2 = _GDIPlus_ImageGetGraphicsContext($hBitmap) 
    
    ; Draw the original opened png into my newly created bitmap
    _GDIPlus_GraphicsDrawImageRect($hGraphic2, $hImage, 0, 0, $w, $h)

    ;Create the font
    $hBrush = _GDIPlus_BrushCreateSolid ("0xFF" & Hex($iRGB, 6))
    $hFormat = _GDIPlus_StringFormatCreate()
    $hFamily = _GDIPlus_FontFamilyCreate ($sFont)
    $hFont = _GDIPlus_FontCreate ($hFamily, $iSize, $iStyle)
    $tLayout = _GDIPlus_RectFCreate ($iX, $iY, 0, 0)
    $aInfo = _GDIPlus_GraphicsMeasureString ($hGraphic2, $sText, $hFont, $tLayout, $hFormat)
    
    ;Draw the font onto the new bitmap
    _GDIPlus_GraphicsDrawStringEx ($hGraphic2, $sText, $hFont, $aInfo[0], $hFormat, $hBrush)
    
    ;Cleanup the no longer needed resources
    _GDIPlus_FontDispose ($hFont)
    _GDIPlus_FontFamilyDispose ($hFamily)
    _GDIPlus_StringFormatDispose ($hFormat)
    _GDIPlus_BrushDispose ($hBrush)
    _GDIPlus_GraphicsDispose ($hGraphic2)
    _GDIPlus_GraphicsDispose ($hGraphic1)

    ;Return the new bitmap
    Return $hBitmap
EndFunc 

Func _ImageResize($newW, $newH)
    Local $GC, $newBmp, $newGC

   ;Create New image
    $GC = _GDIPlus_ImageGetGraphicsContext($oldImage)
    $newBmp = _GDIPlus_BitmapCreateFromGraphics($newW, $newH, $GC)
    $newGC = _GDIPlus_ImageGetGraphicsContext($newBmp)
   ;Draw
    _GDIPlus_GraphicsDrawImageRect($newGC, $oldImage,0,0, $newW, $newH)
   ;Cleanup
   ;_GDIPlus_BitmapDispose($newBmp)
    _GDIPlus_GraphicsDispose($GC)
    _GDIPlus_GraphicsDispose($newGC)
    
    Return $newBmp
EndFunc  ;==>_ImageResize

Share this post


Link to post
Share on other sites

Excellent work! How DOES one place a Child behind the MainGUI? Something to do with z-order but I can't get _WinAPI_SetWindowPos to work with $WS_EX_MDICHILD.


Are you experienced?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0