Subject Re: WIN 11 Borderless Buttons with Rounded Corners
From Mervyn Bick <invalid@invalid.invalid>
Date Tue, 21 Mar 2023 17:51:55 +0200
Newsgroups dbase.getting-started
Attachment(s) round_corner_button.cctest_round_corner_button.wfm

On 2023/03/21 10:15, michael wrote:
> Hi Guys,
>
> Ok, I will give you greater detail in what I am trying to do. Here is a history and request in point form,
....
> 3. I need to take it up a notch, so launching a new brand, website, social media campaign to mirrow the new demographics and current rounded windows style. See pic 2. this is where I am trying to get to and its a design of where we need to be in the current market.

In the past I have "borrowed" code from Marc van den Berghen to create
circular pushbuttons.  This used CreateEllipticRgn() from the Windows32
API.  CreateRoundRectRgn() from the API creates a rectangular region
with rounded corners, which can be altered to suit, but I haven't (yet
:-) ) managed to get this to work properly.

The attached custom pushbutton comes close but it uses
CreateEllipticRgn() and relies on a dBASE shape object to provide the
line round the pushbutton.  The rounding of the corners is unfortunately
not adjustable.

The custom control uses an onOpen event handler internally.  If your
existing pushbuttons use an onOpen event handler it will be necessary to
insert a call to the custom control's onOpen event handler before any
other code.

It is easy enough to write a little program that will add the set
procedure line immediately after a form's class definition and then
replace 'new PUSHBUTTON(this)' with 'new ROUND_CORNER_BUTTON(this)'.

The custom control requires the form metric to be set to pixels.  The
easiest way is to open each form in the IDE, change the metric and then
save.  Acceptable for a few form but a PITA if there are many forms.
Again, it's not a problem to change top, left, width and height values
in a program but the factors to apply depend on the original metric.

Mervyn.


/*

   Filename:   Round_Corner_Button.cc

   Date:       2023-03-21

   Author:     Mervyn Bick

  
   Description: Round_Corner_Button is a pushbutton based on an idea
                          (and code) "borrowed" from  Marc van den Berghen's
                                                        article "The Form Factory" in issue 21 of the dBulletin.
                                                        https://www.jpmartel.com/bulletin.htm
                                                        
                                                        The custom control should be used on a form where
                                                        the metric property is set to pixels.
                                                        
                                                        In the designer the pushbutton will present as a square.
                                                        Resize as appropriate keeping the height and width about
                                                        the same.  When the form opens the pushbutton will set its
                                                        width to match the height.  This ensures any text remains
                                                        centered.
                                                        
                                                        If it is necessary to assign an event handler to the onOpen
                     event the onOpen event in the custom class must be executed
                     before any other code.
                                                        
                                                         function ROUNDBUTTON1_onOpen()
                                                                roundbutton::onOpen()
                        // Other code                        
                                                                return
                        
                        
                      In theory,   CreateRoundRectRgn() from the Windows32 API
                      should create the required shape.  This function allows the
                      rounding of the corners to be set as required.  Unfortunately
                      I have not managed to implement this (yet) so I've used
                      CreateEllipticRgn() combined with a dBASE shape object.   The
                      dBASE shape object does not allow the rounding of the corners
                      to be adjusted.

*/

class Round_Corner_Button( parentObj ) of PushButton( parentObj ) custom
   with (this)
      onOpen = class::ONOPEN
      metric = 6        // Pixels
      height = 65.0
      width = 65.0
      fontsize = 15
      text = 'PB'
      systemtheme := false
   endwith

  function onopen
           local hrgn1
                if this.width <> this.height
                   this.width = this.height
      endif        
            if type("SetWindowRgn") # "FP"        
                        extern CINT SetWindowRgn(CHANDLE, CHANDLE, CLOGICAL) user32
           endif
                if type("CreateRoundRectRgn") # "FP"
                        extern chandle  CreateRoundRectRgn(cint,cint,cint,cint,cint,cint) gdi32
                endif
      if type("CreateEllipticRgn") # "FP"
                        extern chandle  CreateEllipticRgn(cint,cint,cint,cint) gdi32
                endif
      x1 = this.left
      y1 = this.top
      x2 = this.left+this.width
      y2 = this.top+this.height
//           hrgn1=CreateRoundRectRgn(x1,y1,x2,y2,1,1)
           hrgn1=CreateEllipticRgn(this.width-5,5,5,this.width-5)
      setwindowrgn(this.hwnd,hrgn1,true)
      class::addring()
   return
        
        function addRing
      this.outline = new shape(this.parent)
      this.outline.shapestyle := 4
      this.outline.colorNormal := this.colorNormal
      this.outline.top = this.top
      this.outline.left = this.left
      this.outline.width = this.width
      this.outline.height = this.height
      this.outline.penwidth := 1
        return
        
endclass

clear
** END HEADER -- do not remove this line
//
// Generated on 2023-03-21
//
parameter bModal
local f
f = new test_round_corner_buttonForm()
if (bModal)
   f.mdi = false // ensure not MDI
   f.readModal()
else
   f.open()
endif

class test_round_corner_buttonForm of FORM
   set procedure to round_corner_button.cc additive
   with (this)
      metric = 6        // Pixels
      height = 499.0
      left = 115.0
      top = 5.0
      width = 570.0
      text = "Test round corner buttons"
      systemTheme = true
   endwith

   this.ROUND_CORNER_BUTTON1 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON1)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 276.0
      top = 58.0
      width = 65.0
      text = "1"
   endwith

   this.ROUND_CORNER_BUTTON2 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON2)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 353.0
      top = 58.0
      width = 65.0
      text = "2"
   endwith

   this.ROUND_CORNER_BUTTON3 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON3)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 430.0
      top = 58.0
      width = 65.0
      text = "3"
   endwith

   this.ROUND_CORNER_BUTTON4 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON4)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 276.0
      top = 131.0
      width = 65.0
      text = "4"
   endwith

   this.ROUND_CORNER_BUTTON5 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON5)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 353.0
      top = 131.0
      width = 65.0
      text = "5"
   endwith

   this.ROUND_CORNER_BUTTON6 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON6)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 430.0
      top = 131.0
      width = 65.0
      text = "6"
   endwith

   this.ROUND_CORNER_BUTTON7 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON7)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 276.0
      top = 204.0
      width = 65.0
      text = "7"
   endwith

   this.ROUND_CORNER_BUTTON8 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON8)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 353.0
      top = 204.0
      width = 65.0
      text = "8"
   endwith

   this.ROUND_CORNER_BUTTON9 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON9)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 430.0
      top = 204.0
      width = 65.0
      text = "9"
   endwith

   this.ROUND_CORNER_BUTTON10 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON10)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 276.0
      top = 278.0
      width = 65.0
      text = "X"
   endwith

   this.ROUND_CORNER_BUTTON11 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON11)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 353.0
      top = 278.0
      width = 65.0
      text = "0"
   endwith

   this.ROUND_CORNER_BUTTON12 = new ROUND_CORNER_BUTTON(this)
   with (this.ROUND_CORNER_BUTTON12)
      onClick = class::ROUND_CORNER_BUTTON_ONCLICK
      height = 65.0
      left = 430.0
      top = 278.0
      width = 65.0
      text = "Enter"
      colorNormal = "BtnText/0x966ff2"
   endwith


   function ROUND_CORNER_BUTTON_onClick()
      ? this.text+' clicked'
      return

endclass