PlanetSquires Forums

Support Forums => WinFBX - Windows Framework for FreeBASIC => Topic started by: Paul Squires on June 15, 2018, 11:14:53 PM

Title: CXpButton
Post by: Paul Squires on June 15, 2018, 11:14:53 PM
Hi Jose,

I'd like to ask your opinion... Over the years I've had many people wanting to be able to set the foreground and background colors for the standard pushbutton that FireFly used as a control. Given that it is a standard Windows control that didn't allow user specified backcolors, I usually pointed them in the direction of other user created custom controls. For the new designer, I am thinking of just using your CXpButton as the one and only push button for the designer. What do you think? It would make things so much easier and, more importantly, less confusing and more user friendly for novices. If this path is chosen, the only thing that I think would be needed is to modify the control so that the user can specify fore/back colors (when themes are disabled for the control).

Sound good???
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 12:06:02 AM
I wrote it many years ago (XP times) as an exercise of how to write a custom control using visual styles. Today it is not longer needed since you can use image lists with buttons, and I translated it to FreeBasic mainly to practice to write custom controls using a class. I will leave it as it is (you don't need to include it in the designer) and write another with a different name (XP is already vintage) based on it to save coding, with all the changes that you like. I personally dislike coloured buttons, but it is not my business if other people like them.
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 08:28:10 AM
Awesome, thanks Jose! From using the control last night it seemed like the only things missing that really jumped out at me were the fore/back colors and the ability to use any type of image (not just icons and bitmaps) (png, jpg, etc) and to be able to set their transparency backcolor easily. Maybe you could integrate your AfxGdipIconFromRes function, etc.
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 09:46:42 AM
PNGs and othe formats can already be used, e.g. instead of using LoadIcon you can use

Code: [Select]
pXpButton1.SetIcon AfxGdipImageFromFile(ExePath & "/Shutdown_48.png"), XPBI_NORMAL

or other GdiPlus wrappers.


Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 11:14:14 AM
Methods to add support for other image formats. The optional parameter dimPercent canbe used to dim the imape and in combination with bGrayScale to get disabled gray images from a normal image, e.g.:

Code: [Select]
pXpButton1.SetImageFromFile(ExePath & "/Shutdown_48.png", XPBI_NORMAL)
' Reuse the normal image to get a grayed image
pXpButton1.SetImageFromFile(ExePath & "/Shutdown_48.png", XPBI_DISABLED, TRUE, 60, TRUE)

Code: [Select]
' ========================================================================================
' Loads an image from file and sets it as the image of the button.
' - wszPath = Full path of the bitmap file.
' - ImageState =
'      XPBI_NORMAL = 1
'      XPBI_HOT = 2
'      XPBI_DISABLED = 3
' - fRedraw       = TRUE or FALSE (redraws the button to reflect the changes)
' - dimPercent    = Percent of dimming (1-99)
' - bGrayScale    = TRUE or FALSE. Convert to gray scale.
' ========================================================================================
' ========================================================================================
'PRIVATE FUNCTION AfxGdipIconFromFile (BYREF wszFileName AS WSTRING, _
'   BYVAL dimPercent AS LONG = 0, BYVAL bGrayScale AS LONG = FALSE) AS HANDLE
'   FUNCTION = AfxGdipImageFromFile(wszFileName, dimPercent, bGrayScale, IMAGE_ICON, 0)
'END FUNCTION

' ========================================================================================
' Loads an image from a resource file and sets it as the image of the button.
' - hInstance     = [in] A handle to the module whose portable executable file or an accompanying
'                   MUI file contains the resource. If this parameter is NULL, the function searches
'                   the module used to create the current process.
' - wszImageName  = [in] Name of the image in the resource file (.RES). If the image resource uses
'                   an integral identifier, wszImage should begin with a number symbol (#)
'                   followed by the identifier in an ASCII format, e.g., "#998". Otherwise,
'                   use the text identifier name for the image. Only images embedded as raw data
'                   (type RCDATA) are valid. These must be icons in format .png, .jpg, .gif, .tiff.
' - ImageState =
'      XPBI_NORMAL = 1
'      XPBI_HOT = 2
'      XPBI_DISABLED = 3
' - fRedraw       = TRUE or FALSE (redraws the button to reflect the changes)
' - dimPercent    = Percent of dimming (1-99)
' - bGrayScale    = TRUE or FALSE. Convert to gray scale.
' ========================================================================================
PRIVATE SUB CXpButton.SetImageFromRes (BYVAL hInstance AS HINSTANCE, BYREF wszImageName AS WSTRING, BYVAL ImageState AS LONG = XPBI_NORMAL, BYVAL fRedraw AS LONG = FALSE, _
BYVAL dimPercent AS LONG = 0, BYVAL bGrayScale AS LONG = FALSE)
   DIM hIcon AS HICON = AfxGdipIconFromRes(hInstance, wszImageName, dimPercent, bGrayScale)
   this.SetIcon(hIcon, ImageState, fRedraw)
END SUB
' ========================================================================================
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 12:44:11 PM
Tip:

To solve the problem of different icon sizes depending of the DPI setting, you could add fields in the property list for the wanted width and height of the icon and, in the generated code, use:

Code: [Select]
pXpButton.SetImageSize pWindow.ScaleX(width), pWindow.ScaleY(height)

This way, the icon will we draw with the same relative size.
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 01:13:01 PM
Tip:

To solve the problem of different icon sizes depending of the DPI setting, you could add fields in the property list for the wanted width and height of the icon and, in the generated code, use:

Code: [Select]
pXpButton.SetImageSize pWindow.ScaleX(width), pWindow.ScaleY(height)

This way, the icon will we draw with the same relative size.

Sounds good. I will have those settings in the designer for sure. How about icon transparency... for example, when you use your gdi functions to load a png from the resource file and convert them to icon format would we lose and background transparency? Could, say, the topmost left pixel become the color used for transparency? It would be very versatile if you can load images of any type from the resource file and display in the button such that it blends nicely with whatever color the button is currently using as a background.
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 01:34:34 PM
PNG icons support transparency. Therefore you only need to use SetImageFromFile or SetImageFromRes. Nothing else. Gone are the times of bitmaps with a pink background :)

They also support the alpha channel.
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 03:27:56 PM
What I can't get is to change the background color permanently. Since the control is not ownerdraw, it does not receive the WM_CTLCOLORBTN message and Windows reverts to the system colors as soon at it processes DefWindowProcW. You may need a different control.

I will add the new SetImage functions to the original CXpButton as an improvement.
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 04:25:20 PM
Would forcing a setting where the control does not check for m_bIsThemed (basically set it be false) and then set properties to replace calls like GetSysColorBrush(COLOR_BTNFACE) to our own defined colors. Basically, ensure that the control draws using the GDI sections of the CXpButton.UxDrawPushButton function rather than the theme portions? Would that work?
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 04:53:32 PM
I have tried that and the color changes when you click the button, but it reverts to system colors when you release it.
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 05:51:10 PM
I have tried that and the color changes when you click the button, but it reverts to system colors when you release it.
Ah, yes, I see what you mean. I just tried it as well. Looks like it is the DrawFrameControl api that is the culprit. It uses its own colors.
Code: [Select]
            uState = DFCS_BUTTONPUSH
            IF iStateId = PBS_HOT THEN uState = uState OR DFCS_HOT
            IF (lStyle AND BS_FLAT) = BS_FLAT THEN uState = uState OR DFCS_FLAT
            .DrawFrameControl hDc, @rcContent, DFC_BUTTON, uState

Like you said, looks like this will entail having to go full ownerdrawn which is too bad.
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 05:53:13 PM
But changing the order seems to work. I will try and post a modified file.
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 06:00:20 PM
It works. Updated file and an example.
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 06:06:37 PM
A further modification to get it working when the button is toggled.

Code: [Select]
   ' // Draws the button
   IF m_bIsThemed THEN
      ' // Increase 1 pixel to include the edge
      .InflateRect @rc, 1, 1
      ' // Draws the theme-specified border and fills for the "iPartId" and "iStateId".
      .DrawThemeBackground(hTheme, hDc, BP_PUSHBUTTON, iStateId, @rc, NULL)
      ' // Gets the size of the content for the theme-defined background
      .GetThemeBackgroundContentRect(hTheme, hDc, BP_PUSHBUTTON, iStateId, @rc, @rcContent)
   ELSE
      ' // Uses GDI to draw the button
      rcContent = rc
      IF bIsFocused THEN
         IF m_bIsToggle = FALSE OR bIsPressed = FALSE THEN
            .FrameRect hDc, @rcContent, GetSysColorBrush(COLOR_WINDOWTEXT)
         END IF
         .InflateRect @rcContent, -1, -1
      END IF
      IF m_bIsToggle THEN
         IF iStateId = PBS_PRESSED THEN
            .DrawEdge hDc, @rcContent, EDGE_SUNKEN, BF_RECT OR BF_MIDDLE OR BF_SOFT
         ELSE
            IF (lStyle AND BS_FLAT) = BS_FLAT THEN
               .DrawEdge hDc, @rcContent, EDGE_RAISED, BF_RECT OR BF_MIDDLE OR BF_SOFT OR BF_FLAT
            ELSE
               .DrawEdge hDc, @rcContent, EDGE_RAISED, BF_RECT OR BF_MIDDLE OR BF_SOFT
            END IF
         END IF
      ELSE
         IF bIsPressed THEN
            .FrameRect hDc, @rcContent, GetSysColorBrush(COLOR_BTNSHADOW)
         ELSE
            uState = DFCS_BUTTONPUSH
            IF iStateId = PBS_HOT THEN uState = uState OR DFCS_HOT
            IF (lStyle AND BS_FLAT) = BS_FLAT THEN uState = uState OR DFCS_FLAT
            .DrawFrameControl hDc, @rcContent, DFC_BUTTON, uState
         END IF
      END IF
      IF m_hBkgBrush = NULL THEN
         .FillRect hDc, @rcContent, GetSysColorBrush(COLOR_BTNFACE)
      ELSE
         .FillRect hDc, @rcContent, m_hBkgBrush
      END IF
   END IF

What I have done is to move FillRect to the bottom.
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 06:09:32 PM
Okay, I see what you've done... seems to work for as well. Only thing is that you don't get that visual depressed look when the button is pressed and then released.
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 06:11:02 PM
As an aside: I was reading about theming and noticed that the control doesn't respond to WM_THEMECHANGED
Code: [Select]
        case WM_THEMECHANGED:
            if(pData->hTheme)
                CloseThemeData(pData->hTheme);
            pData->hTheme = OpenThemeData(hwnd, wszClass);
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 06:19:31 PM
As an aside: I was reading about theming and noticed that the control doesn't respond to WM_THEMECHANGED
Code: [Select]
        case WM_THEMECHANGED:
            if(pData->hTheme)
                CloseThemeData(pData->hTheme);
            pData->hTheme = OpenThemeData(hwnd, wszClass);
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;


It is not needed. I call OpenThemeData and CloseThemeData in UxDrawPushButton each time that the button is redrawn.
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 06:26:22 PM
Ahhhhhh...... :)
Title: Re: CXpButton
Post by: Paul Squires on June 16, 2018, 06:27:54 PM
Unfortunately, my studying for tonight now has to end as I have to go out for the night. :(

Good series of articles you've no doubt have already read  :)
https://www.codeproject.com/Articles/620045/Custom-Controls-in-Win-API-Visual-Styles

The guy who wrote them also maintains the mCtl project:
http://www.mctrl.org/
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 06:43:59 PM
Unfortunately, my studying for tonight now has to end as I have to go out for the night. :(

Good series of articles you've no doubt have already read  :)
https://www.codeproject.com/Articles/620045/Custom-Controls-in-Win-API-Visual-Styles

The guy who wrote them also maintains the mCtl project:
http://www.mctrl.org/


But this guy still has not learned how to write DPI aware controls :) The mCtl controls are unusable with High DPI settings.

Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 07:05:09 PM
Okay, I see what you've done... seems to work for as well. Only thing is that you don't get that visual depressed look when the button is pressed and then released.

Well, I have modified the code again and we will only lose the depressed look when using custom colors.

Code: [Select]
   ' // Draws the button
   IF m_bIsThemed THEN
      ' // Increase 1 pixel to include the edge
      .InflateRect @rc, 1, 1
      ' // Draws the theme-specified border and fills for the "iPartId" and "iStateId".
      .DrawThemeBackground(hTheme, hDc, BP_PUSHBUTTON, iStateId, @rc, NULL)
      ' // Gets the size of the content for the theme-defined background
      .GetThemeBackgroundContentRect(hTheme, hDc, BP_PUSHBUTTON, iStateId, @rc, @rcContent)
   ELSE
      ' // Uses GDI to draw the button
      rcContent = rc
      IF bIsFocused THEN
         IF m_bIsToggle = FALSE OR bIsPressed = FALSE THEN
            .FrameRect hDc, @rcContent, GetSysColorBrush(COLOR_WINDOWTEXT)
         END IF
         .InflateRect @rcContent, -1, -1
      END IF
      IF m_bIsToggle THEN
         IF iStateId = PBS_PRESSED THEN
            .DrawEdge hDc, @rcContent, EDGE_SUNKEN, BF_RECT OR BF_MIDDLE OR BF_SOFT
         ELSE
            IF (lStyle AND BS_FLAT) = BS_FLAT THEN
               .DrawEdge hDc, @rcContent, EDGE_RAISED, BF_RECT OR BF_MIDDLE OR BF_SOFT OR BF_FLAT
            ELSE
               .DrawEdge hDc, @rcContent, EDGE_RAISED, BF_RECT OR BF_MIDDLE OR BF_SOFT
            END IF
         END IF
      ELSE
         IF m_hBkgBrush = NULL THEN .FillRect hDc, @rcContent, GetSysColorBrush(COLOR_BTNFACE)
         IF bIsPressed THEN
            .FrameRect hDc, @rcContent, GetSysColorBrush(COLOR_BTNSHADOW)
         ELSE
            uState = DFCS_BUTTONPUSH
            IF iStateId = PBS_HOT THEN uState = uState OR DFCS_HOT
            IF (lStyle AND BS_FLAT) = BS_FLAT THEN uState = uState OR DFCS_FLAT
            .DrawFrameControl hDc, @rcContent, DFC_BUTTON, uState
         END IF
      END IF
      IF m_hBkgBrush THEN.FillRect hDc, @rcContent, m_hBkgBrush
   END IF

I don't know what more I can do unless I get the source code of these API functions an rewrite them.
Title: Re: CXpButton
Post by: Josť Roca on June 16, 2018, 07:48:53 PM
I have added support for text foreground and background colors. Also some minor changes, e.g. SetBkgColor changed to SetButtonBkColor.

I also have added SetTextForeDownColor and SetTextBkDownColor to set the colors used when the button is down (pressed or toggled). This is a workaround to provide a clear indication that the button is pressed or toggled.

If you don't need more changes, we can simply rename it as CXpButton.inc, as the original. This way I don't need to change all the documentation of this control.
Title: Re: CXpButton
Post by: Paul Squires on June 17, 2018, 12:36:25 AM
Thanks Jose, yes, rename this one as the original. I will use it in the designer and if I encounter any problems or suggestions for improvements then I will let you know. It seems like it has all of the properties I would need. Tomorrow, I will look at the button in Visual Studio 2017 to see how the fore/back color affects that button and themeing.

Thanks!
Title: Re: CXpButton
Post by: Josť Roca on June 17, 2018, 09:46:36 AM
It is SetTextForeDownColor an appropriate name? What I want to mean is foreground color when the button is down (pressed).
Title: Re: CXpButton
Post by: Paul Squires on June 17, 2018, 09:52:59 AM
Maybe, "SetTextForeColorDown" or "SetTextForeColorPressed" ?

or even, "SetForeColorTextDown" or "SetForeColorTextPressed" ?
Title: Re: CXpButton
Post by: Josť Roca on June 17, 2018, 10:23:31 AM
Changed names to SetTextForeColorDown and SetTextBkColorDown and renamed the include file as the original: CXpButton.inc.
Title: Re: CXpButton
Post by: Paul Squires on June 18, 2018, 09:51:22 AM
Hi Jose, I'm happy to report that I have been able to integrate the CXpButton into the visual designer as a replacement for the standard Windows button (so far, so good). I only really needed to add a call to subclass the control and an additional pointer in order to track the NEW/DELETE sequence for when I create and subsequently destroy the control. Working on integrating all of the CXpButton functionality into the PropertyList. Any issues/problems, I'll let you know. Thanks
Title: Re: CXpButton
Post by: Josť Roca on June 18, 2018, 10:19:09 AM
Excellent. I always have wondered why one of the first questions that every novice asks is how to change the color of a button. The result can be awful if you choose colors using a theme and then the user chooses another theme. The user needs a gui that doesn't strain their eyes. I have seen things like red text against a light green background or dark blue text against a black background.
Title: Re: CXpButton
Post by: Marc Pons on June 19, 2018, 07:15:09 AM
Josť,
You probably have changed your Rar tool to new version, with my installed winrar 3.93 i was not able to uncompress your last attachments.


It would better stay on zip or previous version rar for more compatibiity when sharing

thanks for your tremendous job
Title: Re: CXpButton
Post by: Josť Roca on June 19, 2018, 08:13:59 AM
Same file in .zip format.
Title: Re: CXpButton
Post by: Paul Squires on June 19, 2018, 11:37:17 AM
Also, don't forget that you can always get Jose's latest files from: https://github.com/JoseRoca/WinFBX
Title: Re: CXpButton
Post by: Paul Squires on June 26, 2018, 09:04:11 PM
Should the CXpButton's TextMargin and ImageMargin be adjusted based on DPI setting? It says that the incoming value should be specified as a pixel number (the default is 4 pixels). Should that value be upscaled when the control is drawn?   pWindow->ScaleX(m_TextMargin)
Title: Re: CXpButton
Post by: Josť Roca on June 26, 2018, 09:35:09 PM
Well, when I wrote it, DPI did not still existed... and I had not realized this detail when I did the translation. Maybe we can modify the control to scale this value and also m_ImageWidth, m_ImageHeight and m_ImageMargin.
Title: Re: CXpButton
Post by: Paul Squires on June 26, 2018, 09:47:00 PM
Thanks Jose, yes, I think the control should do the transformation of the ImageMargin and TextMargin values during the drawing routine. (not sure about the image scaling.. maybe let the user do that one in case they manually specify images based on dpi settings. Wouldn't want a 64px image to be scaled even bigger automatically).
Title: Re: CXpButton
Post by: Josť Roca on June 26, 2018, 10:22:08 PM
Then we will scale only the margins.
Title: Re: CXpButton
Post by: Josť Roca on June 26, 2018, 10:57:05 PM
Changed it to scale the margins.
Title: Re: CXpButton
Post by: Paul Squires on June 26, 2018, 11:11:37 PM
Thanks Jose, I will integrate this new version into the visual designer.
Title: Re: CXpButton
Post by: Paul Squires on June 30, 2018, 11:23:04 PM
Hi Jose, I am working on the various properties of the CXpButton. It would seem to me that it would be easier to work with the control if the various items were implemented as Properties rather than functions. There are various functions to set colors for the background and various text states but no functions to retrieve those values. If implemented as properties then the it would eliminate the need to have a corresponding Get function.

eg.

Using Function approach:
SetButtonBkColor
GetButtonBkColor (this function does not exist)

Using Property approach:
ButtonBkColor( byval nValue as COLORREF )
ButtonBkColor () as COLORREF

Is it too late in this control's life to make such a large change? If it is too late, then maybe you could simply add the missing Get functions for the sake of completeness?

Title: Re: CXpButton
Post by: Josť Roca on July 01, 2018, 02:00:42 AM
Now you have both functions and properties:

Code: [Select]
      ' // Properties
      DECLARE PROPERTY Font () AS HFONT
      DECLARE PROPERTY Font (BYVAL hFont AS HFONT)
      DECLARE PROPERTY TextFormat () AS DWORD
      DECLARE PROPERTY TextFormat (BYVAL dwTextFlags AS DWORD)
      DECLARE PROPERTY Cursor () AS HCURSOR
      DECLARE PROPERTY Cursor (BYVAL hCursor AS HCURSOR)
      DECLARE PROPERTY Toggle (BYVAL fToggle AS LONG)
      DECLARE PROPERTY Toggle () AS LONG
      DECLARE PROPERTY ToggleState () AS LONG
      DECLARE PROPERTY ToggleState (BYVAL fState AS LONG)
      DECLARE PROPERTY ImageWidth () AS LONG
      DECLARE PROPERTY ImageWidth (BYVAL nWidth AS LONG)
      DECLARE PROPERTY ImageHeight () AS LONG
      DECLARE PROPERTY ImageHeight (BYVAL nHeight AS LONG)
      DECLARE PROPERTY ImagePos () AS LONG
      DECLARE PROPERTY ImagePos (BYVAL nPos AS LONG)
      DECLARE PROPERTY ImageMargin () AS LONG
      DECLARE PROPERTY ImageMargin (BYVAL nMargin AS LONG)
      DECLARE PROPERTY ButtonState () AS LONG
      DECLARE PROPERTY ImageType () AS LONG
      DECLARE PROPERTY ButtonBkColor () AS COLORREF
      DECLARE PROPERTY ButtonBkColor (BYVAL bkColor AS COLORREF)
      DECLARE PROPERTY TextForeColor () AS COLORREF
      DECLARE PROPERTY TextForeColor (BYVAL textColor AS COLORREF)
      DECLARE PROPERTY TextBkColor () AS COLORREF
      DECLARE PROPERTY TextBkColor (BYVAL textColor AS COLORREF)
      DECLARE PROPERTY TextForeColorDown () AS COLORREF
      DECLARE PROPERTY TextForeColorDown (BYVAL textColor AS COLORREF)
      DECLARE PROPERTY TextBkColorDown () AS COLORREF
      DECLARE PROPERTY TextBkColorDown (BYVAL textColor AS COLORREF)
      DECLARE PROPERTY NormalImageHandle () AS HANDLE
      DECLARE PROPERTY HotImageHandle () AS HANDLE
      DECLARE PROPERTY DisabledImageHandle () AS HANDLE
      DECLARE PROPERTY BkBrush () AS HBRUSH

Functions have the advantage of the additional fRedraw parameter. Using properties on the fly, you may need to call the Redraw method separately.
Title: Re: CXpButton
Post by: Paul Squires on July 01, 2018, 08:02:00 AM
Thanks Jose! Great job as always :)
Title: Re: CXpButton
Post by: Paul Squires on July 01, 2018, 09:35:07 AM
Here's another one.... 

Would be nice if CXpButton handled the WM_SETFONT message. I know that I can set it via the Font property but being able to WM_SETFONT to the control is easier based on the code I am using. WM_SETCURSOR is handled, but not WM_SETFONT.
Title: Re: CXpButton
Post by: Josť Roca on July 01, 2018, 11:49:46 AM
This should work:

Code: [Select]
      CASE WM_SETFONT
         ' // Sets the font that a control is to use when drawing text.
         pButton = CAST(CXpButton PTR, .GetWindowLongPtrW(hwnd, 0))
         IF pButton THEN
            pButton->SetFont(CAST(.HFONT, wParam), lParam)
            EXIT FUNCTION
         END IF
Title: Re: CXpButton
Post by: Paul Squires on July 01, 2018, 07:00:20 PM
Thanks Jose, yes it seems to be working perfectly so far.
Title: Re: CXpButton
Post by: Paul Squires on July 09, 2018, 11:29:21 PM
Hi Jose,

Maybe add code for the button to handle an incoming BM_CLICK message? I am sending the BM_CLICK message to the button designated as the default button when the ENTER key or ESC keys are pressed. This works perfectly for regular push buttons of course, but fails with the CXPButton button because it doesn't handle the BM_CLICK message.
Title: Re: CXpButton
Post by: Josť Roca on July 09, 2018, 11:48:29 PM
I have added:

Code: [Select]
      CASE BM_CLICK
         .SendMessageW hwnd, WM_LBUTTONDOWN, 0, 0
         .SendMessageW hwnd, WM_LBUTTONUP, 0, 0
         EXIT FUNCTION

Not tested yet, but it should work.
Title: Re: CXpButton
Post by: Paul Squires on July 10, 2018, 01:41:22 PM
I doubt that will work because LBUTTONDOWN and LBUTTONUP do hit testing based on the cursor position to determine if the user has clicked the button. When I get home this evening I will work up some code and post it here for you to include in the button class.

Thanks, Paul
Title: Re: CXpButton
Post by: Josť Roca on July 10, 2018, 02:29:51 PM
You're right. I had no time for testing it. Let's see if this works:

Code: [Select]
      CASE BM_CLICK
         IF .IsWindowEnabled(hwnd) = FALSE THEN EXIT FUNCTION
         ' // Redraws the button in pushed state
         pButton = CAST(CXpButton PTR, .GetWindowLongPtrW(hwnd, 0))
         IF pButton = NULL THEN EXIT FUNCTION
         IF pButton->m_bIsToggle THEN
            IF pButton->m_bToggled = FALSE THEN
               pButton->m_bToggled = TRUE
            ELSE
               pButton->m_bToggled = FALSE
            END IF
         END IF
         pButton->m_fState = BST_PUSHED
         pButton->Redraw
         ' // Redraws the button in unpushed state
         pButton->m_fState = 0
         pButton->Redraw
         ' // Set the focus in the button
         .SetFocus hwnd
         ' // Forwards the message to the parent window
         .SendMessageW .GetParent(hwnd), WM_COMMAND, MAKELONG(GetDlgCtrlId(hwnd), BN_CLICKED), CAST(.LPARAM, hwnd)
         EXIT FUNCTION
Title: Re: CXpButton
Post by: Paul Squires on July 10, 2018, 05:20:04 PM
Thanks Jose! I tested it and it seems to be working okay so far  :-)

Title: Re: CXpButton
Post by: Josť Roca on July 29, 2018, 01:22:37 PM
Hi Paul,

I have added the ButtonBkColorDown properties to change the background color of the button when it is pressed or toggled.
Title: Re: CXpButton
Post by: Paul Squires on July 29, 2018, 07:25:20 PM
Hi Josť,

Thanks for the new code. I added a new Button property called "BackColorDown". Seems to be working okay.
Title: Re: CXpButton
Post by: Paul Squires on January 04, 2019, 01:27:58 PM
Hi Josť,

The CXpButton could use two functions similar to the ones that you have for the CImageCtx control. Currently, I have to use the GetWindowLongPtr calls directly during my WM_DESTROY to get the CXpButton pointers. For convenience and consistency it would be nice to have AfxCXpButtonPtr like the AfxCImageCtxPtr functions below.

Code: [Select]
' ========================================================================================
' Returns a pointer to the class given the handle of its associated window handle.
' hCtl = Handle of the image control.
' ========================================================================================
PRIVATE FUNCTION AfxCImageCtxPtr OVERLOAD (BYVAL hCtl AS HWND) AS CImageCtx PTR
   FUNCTION = CAST(CImageCtx PTR, .GetWindowLongPtrW(hCtl, 0))
END FUNCTION
' ========================================================================================
' ========================================================================================
' hParent = Handle of the parent window of the image control.
' cID = Identifier of the image control.
' ========================================================================================
PRIVATE FUNCTION AfxCImageCtxPtr OVERLOAD (BYVAL hParent AS HWND, BYVAL cID AS LONG) AS CImageCtx PTR
   FUNCTION = CAST(CImageCtx PTR, .GetWindowLongPtrW(GetDlgItem(hParent, cID), 0))
END FUNCTION
' ========================================================================================
Title: Re: CXpButton
Post by: Josť Roca on January 04, 2019, 02:26:32 PM
Done.
Title: Re: CXpButton
Post by: Josť Roca on January 04, 2019, 02:37:28 PM
I smile when I remember that I thought of deprecate it, and only adapted it to practice how to implement a custom control using a class :)
Title: Re: CXpButton
Post by: Paul Squires on January 04, 2019, 02:48:58 PM
Excellent - thanks :-) 

That button is one of the main controls in the WinFBE visual designer code output. It is very versatile.
Title: Re: CXpButton
Post by: Paul Squires on January 21, 2019, 03:15:14 PM
Hi Josť,

I had to make a very change to the CTmageCtx.DrawImage function. I had to move the test for the pImage pointer being null down to the block where the image is actually outputted. It now looks like this:

   IF ( pGraphics ) andalso ( pImage )THEN

This enables me to draw the background normal or HOT regardless of whether an image is actually specified.

I have attached the new CImageCtx control code.