Page 2 of 3

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 11:25 am
by Blue
I think i understand the flow of the code... :shock:
So, "Really simple" is exactly what i said to myself too !

But when the drawing mode is changed from Default to Outlined in FlatBorderButtonEvents() or FlatBorderButtonDraw(), the buttons end up with a colored background (not just a border), plus they do no longer revert to their original state once they've been clicked.

So i still can't figure out how to make them start exactly as they currently are, with a border...

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 12:17 pm
by Blue
Ok, after trying a zillion things, now i finally get it.

In order to start off with a bordered button, case 0 in proc FlatBorderButtonDraw() needs an additional box :

Code: Select all

  Case 0
      Box(0,0,OutputWidth(),OutputHeight(),#Black)                    ; for a black border 
      Box(1,1,OutputWidth()-2,OutputHeight()-2,*p\BackGroundColor)    ; the inner part of the button 
All along, I thought changing the Drawing mode to Outlined was the required change, but no.

Again, i bow deeply before Bisonte for a great piece of code. :D
Ah, the beautiful buttons one can now draw....

Kudos to charvista for raising a very interesting topic.

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 12:52 pm
by charvista
Blue wrote:Kudos to charvista for raising a very interesting topic.
:wink:

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 1:11 pm
by Bisonte
Blue wrote:Again, i flip my hat over and before Bisonte for a great piece of code.
The price goes not to me, it goes to my teacher ....

I learn it from the best : The PureBasic Community :!:

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 1:27 pm
by charvista
Blue wrote: Case 0
Box(0,0,OutputWidth(),OutputHeight(),#Black) ; for a black border
Box(1,1,OutputWidth()-2,OutputHeight()-2,*p\BackGroundColor) ; the inner part of the button
Very good, Blue! I have included this in my code as an optional argument (more flexiblity in the colors). Thank you!
I have also modified this original Bisonte's part:

Code: Select all

        x = (OutputWidth()/2) - (TextWidth(*p\Text)/2)
        y = (OutputHeight()/2) - (TextHeight(*p\Text)/2)
        DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
        DrawText(x,y,*p\Text,*p\TextColor)
with this:

Code: Select all

                    If *p\Align=0; Horizontal align center
                        x=(OutputWidth()/2)-(TextWidth(*p\Text)/2)
                    ElseIf *p\Align>0; Horizontal align left
                        x=*p\Align
                    Else; (negative) Horizontal align right
                        x=OutputWidth()-TextWidth(*p\Text)+*p\Align
                    EndIf
                    y=(OutputHeight()/2)-(TextHeight(*p\Text)/2)-1; Vertical alignment always centered in its height
                    DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
                    DrawText(x,y,*p\Text,*p\TextColor)
to adjust alignment positioning... Negative values will right-align the text, which might be nicer in some cases.
Yes, Bisonte's code is really fantastic! :D
Edit: Bisonte, then you had an excellent teacher!!! :D

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 1:38 pm
by charvista
I have to post the whole code, because I have added the Align.i variable, so the snippet in my previous post won't work, as it is incomplete.
Here is the complete procedure code:

Code: Select all

Prototype FlatPrototype(Pointer,Event=0)

Structure flat_border_button_datas
    Gadget.i
    Drawing.flatprototype
    Text.s
    Align.i
    TextColor.i
    InnerColor.i
    BorderColor.i
    BackGroundColorInner.i
    BackGroundColorBorder.i
    Font.i
    ExtraData.i
EndStructure
;*================================================================================================================================*
Procedure zFlatButtonGadget_Draw(*p.flat_border_button_datas,Event=0)
    Protected x,y,th
    If *p
        If IsGadget(*p\Gadget)
            If StartDrawing(CanvasOutput(*p\Gadget))
                    Select Event
                        Case 0
                            DrawingMode(#PB_2DDrawing_Default)
                            Box(0,0,OutputWidth(),OutputHeight(),*p\BackGroundColorBorder)
                            Box(1,1,OutputWidth()-2,OutputHeight()-2,*p\BackGroundColorInner)
                        Case 1
                            DrawingMode(#PB_2DDrawing_Default)
                            Box(0,0,OutputWidth(),OutputHeight(),*p\BorderColor)
                            Box(1,1,OutputWidth()-2,OutputHeight()-2,*p\InnerColor)
                    EndSelect
                    If IsFont(*p\Font)
                        DrawingFont(FontID(*p\Font))
                    EndIf
                    If *p\Align=0; Horizontal align center
                        x=(OutputWidth()/2)-(TextWidth(*p\Text)/2)
                    ElseIf *p\Align>0; Horizontal align left
                        x=*p\Align
                    Else; (negative) Horizontal align right
                        x=OutputWidth()-TextWidth(*p\Text)+*p\Align
                    EndIf
                    y=(OutputHeight()/2)-(TextHeight(*p\Text)/2)-1; Vertical alignment always centered in its height
                    DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
                    DrawText(x,y,*p\Text,*p\TextColor)
                StopDrawing()
            EndIf
        EndIf
    EndIf
EndProcedure
;*================================================================================================================================*
Procedure zFlatButtonGadget(Gadget.i,X.i,Y.i,W.i,H.i,Text.s,Align.i=0,
                             TextColor.i=$000000,BackGroundColorBorder.i=$F0F0F0,BackGroundColorInner=$F0F0F0,
                             InnerColor.i=$FFE0C2,BorderColor.i=$FF9933,FontNumber.i=152)
    Protected *p.flat_border_button_datas=AllocateMemory(SizeOf(flat_border_button_datas))
    Protected ID
    
    If Not *p : ProcedureReturn #False : EndIf
    InitializeStructure(*p,flat_border_button_datas)
    
    ID=CanvasGadget(Gadget,X,Y,W,H)
    
    If Gadget=#PB_Any : Gadget=ID : EndIf
    
    SetGadgetData(Gadget,*p)
    
    *p\Gadget=Gadget
    *p\Text=Text
    *p\TextColor=TextColor
    *p\Align=Align
    *p\BorderColor=BorderColor
    *p\BackGroundColorBorder=BackGroundColorBorder
    *p\BackGroundColorInner=BackGroundColorInner
    *p\InnerColor=InnerColor
    *p\Font=_F(FontNumber,0)
    *p\Drawing=@zFlatButtonGadget_Draw()
    *p\Drawing(*p,0)
    ProcedureReturn ID    
EndProcedure
and you have to substitute your own font:

Code: Select all

*p\Font=_F(FontNumber,0)

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 1:53 pm
by Blue
Yes, that's what so great about Bisonte's code : You can adjust it very easily to get interesting effects.
And all that without having to keep track of a zillion different possible side effects.

For instance, where Bisonte had 2 cases in the drawing proc, i use 3 : normal (0), hover(1) and pressed (2).
Also, by offsetting the boxes 2 or 3 pixels over, for the various cases, you can have colored buttons with a press-down action as pleasant as the system's.

Another change that's significantly useful is refining the events that trigger the redrawing of the buttons.
Where Bisonte offered the following...

Code: Select all

  Select EventType
      Case #PB_EventType_MouseEnter, #PB_EventType_MouseMove, #PB_EventType_LeftButtonDown, #PB_EventType_RightButtonDown
         *p\Draw(*p, 1)
      Default
         *p\Draw(*p, 0)
  EndSelect            
you could do the following, adding flexibility to the operation :

Code: Select all

   Select EventType
       Case #PB_EventType_MouseEnter, #PB_EventType_LeftButtonUp
           *p\Draw(*p, #hover)
       Case #PB_EventType_MouseLeave
           *p\Draw(*p, #Normal)
       Case #PB_EventType_LeftButtonDown
           *p\Draw(*p, #pressed)
   EndSelect            
When i think of all the complicated spaghetti code i wrote to get a hovering effect on buttons :oops: , i feel humbled by Bisonte's code. So clear and manageable.

Where were you Bisonte when we needed you for the last 6 years ??? :D

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 2:30 pm
by charvista
Thank you for the update, Blue! I haved implemented it too!
When pressed, the button now can have a different color and border! Super!
New idea: when pressed, you can even easily draw the text 1 or 2 pixels to the right and/or lower, to give a more professional effect (with shadow?)!! As well a parameter to make the shifting optional!
Yes, there are endless possibilities.....
:wink:

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 3:31 pm
by Blue
If i may, i'd like to post a complete example

Code: Select all

  >>> Code removed 
  >>>  replaced by the example in the following page
changes :
- replaced the #Normal constant by #buttonNormal because #Normal is already pre-defined in PureBasic
- the other 2 constants were then renamed along this pattern
- the #buttonNormal was not used in every instance where it was required

Re: Flat button with border when hovered ?

Posted: Sun Apr 14, 2013 3:42 pm
by Blue
Charvista, post an example of the modifications you've implemented.

This is the most fun i've had in a long time.
All of a sudden, i've learned an awful lot of new and useful things in a very short time.

In spite of all the snow on the front lawn, Spring must have arrived... How else can this be explained ? :)

Re: Flat button with border when hovered ?

Posted: Mon Apr 15, 2013 9:09 am
by Bisonte
a litte improvement ...
that "marks" the last leftclicked gadget.

Code: Select all

EnableExplicit
;
Prototype flatprototype(Pointer, Event = 0)
;
Structure flat_border_button_datas
 
  Gadget.i
  Drawing.flatprototype
  Text.s
  TextColor.i
  InnerColor.i
  BorderColor.i
  BackGroundColor.i
  Font.i
  ExtraData.i
 
EndStructure
;
Global lastgadget.i
;
Procedure FlatBorderButtonDraw(*p.flat_border_button_datas, Event = 0)
 
  Protected x, y, th
 
  If *p
    If IsGadget(*p\Gadget)

      If StartDrawing(CanvasOutput(*p\Gadget))
        Select Event
          Case 0
            ; »»» The New Segment
            DrawingMode(#PB_2DDrawing_Default)
            If lastgadget = *p\Gadget
              Box(0,0,OutputWidth(),OutputHeight(),*p\BorderColor) 
              Box(1,1,OutputWidth()-2,OutputHeight()-2,*p\BackGroundColor)                  
            Else
              Box(0,0,OutputWidth(),OutputHeight(),*p\BackGroundColor)
            EndIf
            ; »»» The New Segment Ends
          Case 1
            DrawingMode(#PB_2DDrawing_Default)
            Box(0,0,OutputWidth(),OutputHeight(),*p\BorderColor) 
            Box(1,1,OutputWidth()-2,OutputHeight()-2,*p\InnerColor)           
        EndSelect
                   
        If IsFont(*p\Font)
          DrawingFont(FontID(*p\Font))
        EndIf
        x = (OutputWidth()/2) - (TextWidth(*p\Text)/2)
        y = (OutputHeight()/2) - (TextHeight(*p\Text)/2)
        DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
        DrawText(x,y,*p\Text,*p\TextColor)
       
        StopDrawing()
      EndIf
    EndIf
  EndIf
 
EndProcedure
;
Procedure FlatBorderButton(Gadget, x, y, Width, Height, Text.s, TextColor, BackGroundColor, InnerColor, BorderColor, Font)
 
  Protected *p.flat_border_button_datas = AllocateMemory(SizeOf(flat_border_button_datas))
  Protected ID
 
  If Not *p : ProcedureReturn #False : EndIf
  InitializeStructure(*p, flat_border_button_datas)
 
  ID = CanvasGadget(Gadget, x, y, Width, Height)
 
  If Gadget = #PB_Any : Gadget = ID : EndIf
 
  SetGadgetData(Gadget, *p)
 
  *p\Gadget = Gadget
  *p\Text   = Text
  *p\BorderColor = BorderColor
  *p\BackGroundColor = BackGroundColor
  *p\InnerColor = InnerColor
  *p\Font = Font
  *p\Drawing = @FlatBorderButtonDraw()
 
  *p\Drawing(*p, 0)
  
  ProcedureReturn ID
 
EndProcedure
;
Procedure FlatBorderButtonEvents(Gadget, Event, EventType)
 
  Protected *p.flat_border_button_datas
  Protected *q.flat_border_button_datas ; »»» need to declare the last active gadget
  
  If IsGadget(Gadget)
    *p = GetGadgetData(Gadget)
    If *p
      If Event = #PB_Event_Gadget
        Select EventType
          Case #PB_EventType_MouseEnter, #PB_EventType_MouseMove, #PB_EventType_RightButtonDown
            *p\Drawing(*p, 1)
            
          Case #PB_EventType_LeftButtonDown ; »»» declares the lastgadget to the new click and delete the old
            If IsGadget(lastgadget)
              *q = GetGadgetData(lastgadget)
              lastgadget = *p\Gadget
              If *q
                *q\Drawing(*q, 0)
              EndIf
            EndIf
            lastgadget = *p\Gadget
            *p\Drawing(*p, 1)
          
          Default
            *p\Drawing(*p, 0)
        EndSelect   
        
      EndIf
    EndIf
  EndIf
   
EndProcedure
;
DisableExplicit

OpenWindow(0,200,300,800,600,"TestWindow")

Font = LoadFont(#PB_Any, "Segoe UI", 9)

FlatBorderButton(1, 20, 25, 300, 25, "Printer", 0, $F0F0F0, $FFE0C2, $FF9933, Font)
FlatBorderButton(2, 20, 50, 300, 25, "Computer", 0, $F0F0F0, $FFE0C2, $FF9933, Font)
FlatBorderButton(3, 20, 75, 300, 25, "Mouse", 0, $F0F0F0, $FFE0C2, $FF9933, Font)
FlatBorderButton(4, 20, 100, 300, 25, "Keyboard", 0, $F0F0F0, $FFE0C2, $FF9933, Font)
FlatBorderButton(5, 20, 125, 300, 25, "Hard Disk", 0, $F0F0F0, $FFE0C2, $FF9933, Font)

*p.flat_border_button_datas

Repeat
  Event = WaitWindowEvent()
 
  Select Event
    Case #PB_Event_LeftClick ; »»» need to delete the last mark if click somewhere in window
      If IsGadget(lastgadget)
        *p = GetGadgetData(lastgadget)
        If *p
          lastgadget = -1
          *p\Drawing(*p, 0)
        EndIf
      EndIf      
      lastgadget = -1 ; »»» make sure that no gadget can have this number
      
    Case #PB_Event_Gadget
      FlatBorderButtonEvents(EventGadget(), Event, EventType())
      Select EventType()
        Case #PB_EventType_LeftClick
          Select EventGadget()
            Case 1
              Debug "Click on Printer"
            Case 2
              Debug "Click on Computer"
            Case 3
              Debug "Click on Mouse"
            Case 4
              Debug "Click on Keyboard"
            Case 5
              Debug "Click on HardDisk"
          EndSelect         
      EndSelect
     
    Case #PB_Event_CloseWindow
      Quit = 1
     
  EndSelect
 
Until Quit > 0 

Re: Flat button with border when hovered ?

Posted: Mon Apr 15, 2013 7:59 pm
by em_uk
It's quite amusing really. Back when I started programming on the PC & Amiga the buttons looked like this, back then we tried to make them look 3D.

Years after 3D has been perfected, we are moving back to flat looking buttons :)

Re: Flat button with border when hovered ?

Posted: Mon Apr 15, 2013 8:14 pm
by Blue
em_uk wrote:It's quite amusing really [...] Years after 3D has been perfected, we are moving back to flat looking buttons :)
+1 :D Excellent observation.
Same goes for Operating systems : witness the new old look of Windows 8 !

I think i finally understand the meaning of "Back to the Future".

Re: Flat button with border when hovered ?

Posted: Mon Apr 15, 2013 8:22 pm
by davido
Flat, Maybe.

Nice Work. Looks great from here. :D

Re: Flat button with border when hovered ?

Posted: Mon Apr 15, 2013 8:32 pm
by charvista
Thank you Bisonte, for this amazing improvement. In fact, I have done this too, but outside of the procedure. But doing it inside the procedure is indeed a lot more convenient!
Your code has been assimilated. Resistance is futile! :mrgreen:
em_uk wrote:Years after 3D has been perfected, we are moving back to flat looking buttons :)
I am also programming things inspired from Windows 3.11.... and even from IBM AS/400.
So yes, "retro" to recreate old things with newest technologies, that's "nostalgia".
And yes, I agree with Blue, for calling that "Back to the Future"!

But "Flat" is not always good. In Windows 8, the scrollbars are hard to find, because there is too few contrast. I hope Windows 9 will go back to Windows XP or 2000-style for the scrollbars and ListIconGadget's titles, where the contrast was perfect and nice looking.