Page 1 of 2

Text over ImageButton()

Posted: Wed Apr 02, 2008 5:15 pm
by Rook Zimbabwe
OK Aside from creating the picture with the text already in it... is there a way to use an imagebutton and have TEXT floating over the top that could be changed? Easily? :D You know... by some lazy idiot like me?

Posted: Wed Apr 02, 2008 7:01 pm
by Fluid Byte
Use ownerdraw buttons.

Posted: Wed Apr 02, 2008 10:17 pm
by Rook Zimbabwe
A search for ownerdrawn has not shown me very much in the way of insight... Anyone know if a thread?

Posted: Wed Apr 02, 2008 10:32 pm
by Mistrel
Why don't you draw text onto the image that's displayed on the gadget?

Posted: Wed Apr 02, 2008 11:08 pm
by Sparkie
This may be a little more than you need Rook, but it should help you get started. ;)

http://www.purebasic.fr/english/viewtop ... 458#227458

Posted: Thu Apr 03, 2008 2:32 am
by Sparkie
Here's an abbreviated version for you Rook.

Code: Select all

UseJPEGImageDecoder()
Procedure myWindowCallback(hwnd, msg, wParam, lParam) 
  result = #PB_ProcessPureBasicEvents 
  Select msg 
    Case #WM_DRAWITEM 
      *dis.DRAWITEMSTRUCT = lParam 
      If *dis\CtlType = #ODT_BUTTON 
        buttonBrush = GetGadgetData(0)
        buttonNum = *dis\CtlID 
        SetBkMode_(*dis\hdc, #TRANSPARENT) 
        doFlags = #DFCS_BUTTONPUSH | #DFCS_ADJUSTRECT 
        DrawFocusRect = #False
        Select *dis\itemState 
          Case #ODS_DISABLED 
            SetTextColor_(*dis\hdc, RGB(125, 125, 125)) 
          Case #ODS_FOCUS 
            DrawFocusRect = #True
          Case #ODS_FOCUS | #ODS_SELECTED 
            doFlags = #DFCS_BUTTONPUSH | #DFCS_PUSHED | #DFCS_ADJUSTRECT 
        EndSelect 
      EndIf 
      DrawFrameControl_(*dis\hdc, *dis\rcItem, #DFC_BUTTON, doFlags) 
      FillRect_(*dis\hdc, *dis\rcItem, buttonBrush) 
      DrawText_(*dis\hdc, GetGadgetText(buttonNum), Len(GetGadgetText(buttonNum)), *dis\rcItem, #DT_CENTER | #DT_SINGLELINE | #DT_VCENTER) 
      If DrawFocusRect
        DrawFocusRect_(*dis\hdc, *dis\rcItem)
      EndIf
  EndSelect 
  ProcedureReturn result 
EndProcedure 

If OpenWindow(0, 100, 100, 500, 400, "Custom Button", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  SetWindowCallback(@myWindowCallback()) 
  ButtonGadget(0, 10, 10, 100, 100, "Ownerdrawn") 
  ButtonGadget(1, 120, 10, 100, 100, "Normal") 
  bStyle = GetWindowLong_(GadgetID(0), #GWL_STYLE) 
  SetWindowLong_(GadgetID(0), #GWL_STYLE, bStyle &~#BS_PUSHBUTTON | #BS_OWNERDRAW) 
  ;... Create button background brush 
  buttonBrush = CreatePatternBrush_(CatchImage(0, ?myImage)) 
  SetGadgetData(0, buttonBrush) 
   
  Repeat 
    event = WaitWindowEvent() 
  Until event = #PB_Event_CloseWindow 
EndIf 
DeleteObject_(buttonBrush) 
End 
DataSection
myImage:
Data.b $FF,$D8,$FF,$E0,$00,$10,$4A,$46,$49,$46,$00,$01,$01,$01,$00,$60
Data.b $00,$60,$00,$00,$FF,$DB,$00,$43,$00,$28,$1C,$1E,$23,$1E,$19,$28
Data.b $23,$21,$23,$2D,$2B,$28,$30,$3C,$64,$41,$3C,$37,$37,$3C,$7B,$58
Data.b $5D,$49,$64,$91,$80,$99,$96,$8F,$80,$8C,$8A,$A0,$B4,$E6,$C3,$A0
Data.b $AA,$DA,$AD,$8A,$8C,$C8,$FF,$CB,$DA,$EE,$F5,$FF,$FF,$FF,$9B,$C1
Data.b $FF,$FF,$FF,$FA,$FF,$E6,$FD,$FF,$F8,$FF,$C0,$00,$0B,$08,$00,$64
Data.b $00,$64,$01,$01,$11,$00,$FF,$C4,$00,$17,$00,$01,$01,$01,$01,$00
Data.b $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02,$01,$00,$03,$FF
Data.b $C4,$00,$1A,$10,$01,$01,$01,$01,$01,$01,$01,$00,$00,$00,$00,$00
Data.b $00,$00,$00,$00,$00,$01,$11,$02,$12,$21,$31,$FF,$DA,$00,$08,$01
Data.b $01,$00,$00,$3F,$00,$EA,$59,$AD,$39,$5B,$06,$A6,$A6,$B6,$A6,$B6
Data.b $B1,$4F,$8C,$5E,$4B,$92,$1A,$E7,$D0,$DA,$96,$A6,$AC,$AB,$0A,$16
Data.b $36,$3A,$79,$1A,$A9,$5C,$EC,$1B,$11,$11,$61,$F2,$E9,$21,$48,$56
Data.b $8B,$35,$F8,$36,$0D,$83,$60,$D8,$D8,$B2,$1C,$98,$71,$D2,$0D,$69
Data.b $19,$A8,$54,$4B,$13,$16,$72,$53,$93,$9C,$EA,$F9,$C6,$2B,$C8,$5F
Data.b $83,$E9,$35,$64,$6C,$6B,$12,$43,$9C,$9F,$92,$9C,$AF,$91,$F2,$B5
Data.b $CB,$B7,$2E,$92,$53,$94,$A2,$B1,$73,$0D,$A5,$2D,$F8,$C1,$6B,$9F
Data.b $6E,$3D,$0C,$28,$7C,$D3,$BF,$83,$A5,$3A,$2F,$49,$E8,$B9,$E8,$B4
Data.b $77,$E3,$9F,$55,$CB,$A1,$C5,$91,$D3,$95,$B4,$2D,$59,$D3,$7A,$69
Data.b $5D,$25,$2D,$0B,$46,$D1,$A8,$B1,$65,$5B,$42,$A5,$A9,$29,$F2,$E9
Data.b $17,$41,$2D,$0B,$59,$4A,$35,$14,$C5,$90,$A2,$EB,$68,$DA,$35,$0A
Data.b $45,$65,$FD,$16,$D6,$D6,$95,$75,$75,$2A,$34,$56,$66,$4A,$8A,$2B
Data.b $09,$FF,$D9
EndDataSection

Posted: Thu Apr 03, 2008 4:34 am
by netmaestro
Nice job, Sparkie! Very compact and functional.

I did see one difference in the way your ownerdrawn button performs compared to the standard one. If you click it a lot quickly, the standard one presses and releases as fast as you can work the mouse while the ownerdrawn version is quite "speed limited". Try it, see what I mean?

It took me a while to pinpoint this one, but I came to the conclusion eventually that faster clicks are being taken as doubleclick events from the button and are thus ignored as buttons don't natively process doubleclicks. The two single clicks get eaten up. So:

Code: Select all

Procedure ButtonCallback(hwnd, msg, wparam, lparam)
  oldproc = GetProp_(hwnd, "oldproc")
  Select msg
    Case #WM_NCDESTROY
      RemoveProp_(hwnd, "oldproc")
    Case #WM_LBUTTONDBLCLK
      PostMessage_(hwnd, #WM_LBUTTONDOWN,0,0)
  EndSelect
  ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
EndProcedure

;
;button creation here
;
SetProp_(GadgetID(0),"oldproc", SetWindowLong_(GadgetID(0),#GWL_WNDPROC,@ButtonCallback()))
Adding this bit of code makes your ownerdrawn button perform like the standard one in this regard, here at least.

The only other thing would be that you could lower the text a pixel or two for the pushed state, then it's pretty much perfect.

Posted: Thu Apr 03, 2008 10:58 am
by srod
Nice tip. Thanks. 8)

Posted: Thu Apr 03, 2008 1:23 pm
by Fluid Byte
Actually you can just remove the class style using this line:

Code: Select all

SetClassLong_(hWnd,#GCL_STYLE,GetClassLong_(hWnd,#GCL_STYLE) ! #CS_DBLCLKS)
Here's a little demo for you:

Code: Select all

Procedure WindowCallback(hWnd,uMsg,wParam,lParam)
    Select uMsg
        Case #WM_DRAWITEM
       *lpdis.DRAWITEMSTRUCT = lParam
       
       SetBkMode_(*lpdis\hDC,#TRANSPARENT)
       
       If *lpdis\itemState & #ODS_SELECTED
          SelectObject_(*lpdis\hDC,GetStockObject_(#BLACK_BRUSH))         
          SetTextColor_(*lpdis\hDC,#White)
       Else
          SelectObject_(*lpdis\hDC,GetStockObject_(#WHITE_BRUSH))          
          SetTextColor_(*lpdis\hDC,0)      
       EndIf
       
       Rectangle_(*lpdis\hDC,0,0,*lpdis\rcItem\right,*lpdis\rcItem\bottom)
       DrawText_(*lpdis\hDC,GetGadgetText(0),-1,*lpdis\rcItem,#DT_CENTER | #DT_VCENTER | #DT_SINGLELINE)
       
       ProcedureReturn 0
    EndSelect
     
    ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0,0,0,320,240,"void",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CreateGadgetList(WindowID(0))
ButtonGadget(0,5,5,150,25,"OWNERDRAW BUTTON",#BS_OWNERDRAW)

SetClassLong_(GadgetID(0),#GCL_STYLE,GetClassLong_(GadgetID(0),#GCL_STYLE) ! #CS_DBLCLKS)

SetWindowCallback(@WindowCallback())

While WaitWindowEvent() ! #PB_Event_CloseWindow : Wend

Posted: Thu Apr 03, 2008 1:43 pm
by Sparkie
Thanks netmaestro, I never even noticed that doubleclick issue before. In addition to your fix, you can also removes the CS_DBLCLKS from the button. The only drawback is you won't be able to trap doubleclicks from any and all buttons in your app.

Here's the modified code using my fix and adding netmaesto's drop-text effect. It's no better than what netmaestro posted, it's just an alternative for you to choose from. ;)

Code: Select all

UseJPEGImageDecoder() 

Procedure myWindowCallback(hwnd, msg, wParam, lParam) 
  result = #PB_ProcessPureBasicEvents 
  Select msg 
    Case #WM_DRAWITEM 
      *dis.DRAWITEMSTRUCT = lParam 
      If *dis\CtlType = #ODT_BUTTON 
        buttonBrush = GetGadgetData(0) 
        buttonNum = *dis\CtlID 
        SetBkMode_(*dis\hdc, #TRANSPARENT) 
        doFlags = #DFCS_BUTTONPUSH | #DFCS_ADJUSTRECT 
        DrawFocusRect = #False 
        Select *dis\itemState 
          Case #ODS_DISABLED 
            SetTextColor_(*dis\hdc, RGB(125, 125, 125)) 
          Case #ODS_FOCUS 
            DrawFocusRect = #True 
            pressed = #False
          Case #ODS_FOCUS | #ODS_SELECTED 
            DrawFocusRect = #True
            pressed = #True
            doFlags = #DFCS_BUTTONPUSH | #DFCS_PUSHED | #DFCS_ADJUSTRECT 
        EndSelect 
      EndIf 
      DrawFrameControl_(*dis\hdc, *dis\rcItem, #DFC_BUTTON, doFlags) 
      FillRect_(*dis\hdc, *dis\rcItem, buttonBrush) 
      If DrawFocusRect And pressed
        DrawFocusRect_(*dis\hdc, *dis\rcItem) 
        *dis\rcItem\top + 2
        *dis\rcItem\left + 2
        DrawText_(*dis\hdc, GetGadgetText(buttonNum), Len(GetGadgetText(buttonNum)), *dis\rcItem, #DT_CENTER | #DT_SINGLELINE | #DT_VCENTER) 
      ElseIf DrawFocusRect And Not pressed
        DrawFocusRect_(*dis\hdc, *dis\rcItem) 
        DrawText_(*dis\hdc, GetGadgetText(buttonNum), Len(GetGadgetText(buttonNum)), *dis\rcItem, #DT_CENTER | #DT_SINGLELINE | #DT_VCENTER) 
      Else
        DrawText_(*dis\hdc, GetGadgetText(buttonNum), Len(GetGadgetText(buttonNum)), *dis\rcItem, #DT_CENTER | #DT_SINGLELINE | #DT_VCENTER) 
      EndIf 
  EndSelect 
  ProcedureReturn result 
EndProcedure 

If OpenWindow(0, 100, 100, 500, 400, "Custom Button", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  SetWindowCallback(@myWindowCallback()) 
  ButtonGadget(0, 10, 10, 100, 100, "Ownerdrawn") 
  ButtonGadget(1, 120, 10, 100, 100, "Normal") 
  bStyle = GetWindowLong_(GadgetID(0), #GWL_STYLE) 
  SetWindowLong_(GadgetID(0), #GWL_STYLE, bStyle &~#BS_PUSHBUTTON | #BS_OWNERDRAW | #BS_NOTIFY) 
  ;... Create button background brush 
  buttonBrush = CreatePatternBrush_(CatchImage(0, ?myImage)) 
  SetGadgetData(0, buttonBrush) 
  SetClassLong_(GadgetID(0), #GCL_STYLE, GetClassLong_(GadgetID(0), #GCL_STYLE) &(~#CS_DBLCLKS))
  
  Repeat 
    event = WaitWindowEvent() 
  Until event = #PB_Event_CloseWindow 
EndIf 
DeleteObject_(buttonBrush) 
End 
DataSection 
  myImage: 
  Data.b $FF,$D8,$FF,$E0,$00,$10,$4A,$46,$49,$46,$00,$01,$01,$01,$00,$60 
  Data.b $00,$60,$00,$00,$FF,$DB,$00,$43,$00,$28,$1C,$1E,$23,$1E,$19,$28 
  Data.b $23,$21,$23,$2D,$2B,$28,$30,$3C,$64,$41,$3C,$37,$37,$3C,$7B,$58 
  Data.b $5D,$49,$64,$91,$80,$99,$96,$8F,$80,$8C,$8A,$A0,$B4,$E6,$C3,$A0 
  Data.b $AA,$DA,$AD,$8A,$8C,$C8,$FF,$CB,$DA,$EE,$F5,$FF,$FF,$FF,$9B,$C1 
  Data.b $FF,$FF,$FF,$FA,$FF,$E6,$FD,$FF,$F8,$FF,$C0,$00,$0B,$08,$00,$64 
  Data.b $00,$64,$01,$01,$11,$00,$FF,$C4,$00,$17,$00,$01,$01,$01,$01,$00 
  Data.b $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02,$01,$00,$03,$FF 
  Data.b $C4,$00,$1A,$10,$01,$01,$01,$01,$01,$01,$01,$00,$00,$00,$00,$00 
  Data.b $00,$00,$00,$00,$00,$01,$11,$02,$12,$21,$31,$FF,$DA,$00,$08,$01 
  Data.b $01,$00,$00,$3F,$00,$EA,$59,$AD,$39,$5B,$06,$A6,$A6,$B6,$A6,$B6 
  Data.b $B1,$4F,$8C,$5E,$4B,$92,$1A,$E7,$D0,$DA,$96,$A6,$AC,$AB,$0A,$16 
  Data.b $36,$3A,$79,$1A,$A9,$5C,$EC,$1B,$11,$11,$61,$F2,$E9,$21,$48,$56 
  Data.b $8B,$35,$F8,$36,$0D,$83,$60,$D8,$D8,$B2,$1C,$98,$71,$D2,$0D,$69 
  Data.b $19,$A8,$54,$4B,$13,$16,$72,$53,$93,$9C,$EA,$F9,$C6,$2B,$C8,$5F 
  Data.b $83,$E9,$35,$64,$6C,$6B,$12,$43,$9C,$9F,$92,$9C,$AF,$91,$F2,$B5 
  Data.b $CB,$B7,$2E,$92,$53,$94,$A2,$B1,$73,$0D,$A5,$2D,$F8,$C1,$6B,$9F 
  Data.b $6E,$3D,$0C,$28,$7C,$D3,$BF,$83,$A5,$3A,$2F,$49,$E8,$B9,$E8,$B4 
  Data.b $77,$E3,$9F,$55,$CB,$A1,$C5,$91,$D3,$95,$B4,$2D,$59,$D3,$7A,$69 
  Data.b $5D,$25,$2D,$0B,$46,$D1,$A8,$B1,$65,$5B,$42,$A5,$A9,$29,$F2,$E9 
  Data.b $17,$41,$2D,$0B,$59,$4A,$35,$14,$C5,$90,$A2,$EB,$68,$DA,$35,$0A 
  Data.b $45,$65,$FD,$16,$D6,$D6,$95,$75,$75,$2A,$34,$56,$66,$4A,$8A,$2B 
  Data.b $09,$FF,$D9 
EndDataSection 
*Edit* Thanks Fluid BYte, you post faster than I type. GMTA :)

Posted: Thu Apr 03, 2008 3:08 pm
by Rook Zimbabwe
Thanks guys! This is all incredible!!! :D

Now to test and see if this will work with the 121 buttons I redraw each time a new menupage button is selected... 8) Single Clicks are what I wanted to insure as well... that tip was great!

I just wish this wasn't API so I could use it on MAC and Linux as well!

8)

Posted: Thu Apr 03, 2008 4:24 pm
by Fluid Byte
I thought Sparkman ignored me but we posted in the same minute. Image

Posted: Thu Apr 03, 2008 5:04 pm
by Sparkie
I was 20 minutes behind you Fluid Byte. I had my post ready to go when I got sidetracked (at work). Then I come back to my computer to post and see you had already snuck in there with your code. :P

I would never ignore you Fluid Byte. It's been a pleasure to see your nice side around here latelty :)

Posted: Thu Apr 03, 2008 5:25 pm
by srod
You must be very busy at work sparks! :wink:

Posted: Thu Apr 03, 2008 7:19 pm
by Derek
Just tried this on my laptop running Vista and unfortunately Sparkies code doesn't seem to do anything other than have a button with a nice background, no droptext, no moving or highlighting.

Fluid Bytes code does work and flashes the colour of the button whenever clicked on.

I'm guessing this is a Vista issue as I haven't tried it on my XP computer but it seems to be working for others. :?

Unless of course there isn't supposed to be any indication that the button was pressed, in which case just ignore me. :wink: