Page 1 of 1

Image as container background?

Posted: Thu Jan 30, 2014 6:05 pm
by Poshu
I know how to apply an image as a container background on windows, is it possible to do the same thing on osx?

I *suppose* it should have something to do with CocoaMessage(0, ContainerID, "setBackgroundColor:", CocoaMessage(0, 0, "NSColor colorWithPatternImage:", ImageID(0))), since pb's container is a subclassed NSBox, but I can't get it to work.

Re: Image as container background?

Posted: Thu Jan 30, 2014 7:50 pm
by Poshu
aaaaand answered myself (next time, try a few more minutes before asking)

Code: Select all

CocoaMessage(0,gadget,"setFillColor:",CocoaMessage(0, 0, "NSColor colorWithPatternImage:", ImageID(0)))
It might serves someone ;3

Re: Image as container background?

Posted: Thu Jan 30, 2014 8:50 pm
by Shardik
Too late...
But you also should have given us the hint that your code only works if the ContainerGadget (NSBox) has a BoxType of NSBoxCustom and a BorderType of NSLineBorder... :wink:

Update: Oh sorry, BoxType NSBoxCustom is PB's default... :oops:
I found several Objective-C examples where the authors fell into that trap !
NSBox Class Reference for setFillColor: wrote:Special Considerations

Functional only when the receiver’s box type (boxType) is NSBoxCustom and its border type (borderType) is NSLineBorder.
I have now tested this on Snow Leopard and Mavericks: the BorderType doesn't matter (0..3 all work) but the BoxType has indeed to be NSBoxCustom...

This is a working code example:

Code: Select all

#NSBoxCustom = 4
#NSLineBorder = 1

UseJPEGImageDecoder()

If LoadImage(0, #PB_Compiler_Home + "Examples/3D/Data/Textures/Clouds.jpg")
  OpenWindow(0, 270, 100, 300, 300, "Container with background image")
  ContainerGadget(0, 10, 10, 280, 280)

  ; ----- When setting a background image for an NSBox (ContainerGadget) the
  ;       BoxType has to be #NSBoxCustom and the BorderType #NSLineBorder !
  CocoaMessage(0, GadgetID(0), "setBoxType:", #NSBoxCustom)
  CocoaMessage(0, GadgetID(0), "setBorderType:", #NSLineBorder)
  ; ----- Set image as background image of ContainerGadget
  CocoaMessage(0, GadgetID(0), "setFillColor:",
    CocoaMessage(0, 0, "NSColor colorWithPatternImage:", ImageID(0)))

  Repeat
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: Image as container background?

Posted: Thu Jan 30, 2014 10:21 pm
by Wolfram
can you also give a example for setCornerRadius:

Thanks

Re: Image as container background?

Posted: Fri Jan 31, 2014 7:07 am
by Danilo
Wolfram wrote:can you also give a example for setCornerRadius:

Code: Select all

  CocoaMessage(0, GadgetID(0), "setBoxType:"   , #NSBoxCustom)
  CocoaMessage(0, GadgetID(0), "setBorderType:", #NSLineBorder)

  radius.f = 20.0
  CocoaMessage(0,GadgetID(0),"setCornerRadius:@",@radius)

Re: Image as container background?

Posted: Fri Jan 31, 2014 7:32 am
by Danilo
BTW, the background image for container gadget has also a problem when the window
is resize-able.

I wanted to set a pattern image as window background:

Code: Select all

Procedure SetWindowBackgroundPattern(win,imageID)
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
        CocoaMessage(@color,0,"NSColor colorWithPatternImage:",imageID)
        If color
            CocoaMessage(0,WindowID(win),"setBackgroundColor:",color) ; note: pattern begins at the bottom
            CocoaMessage(0,WindowID(win),"update")                    ;       of the window (not good with
            ProcedureReturn color                                     ;       resize-able windows)
        EndIf
    CompilerElseIf #PB_Compiler_OS = #PB_OS_Windows
        brush = CreatePatternBrush_(imageID)
        If brush
            SetClassLongPtr_(WindowID(win),#GCL_HBRBACKGROUND,brush)
            InvalidateRect_(WindowID(win),0,#True)
            UpdateWindow_(WindowID(win))
            ProcedureReturn brush
        EndIf
    CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
    CompilerElse
        CompilerError "Unknown Platform for SetWindowBackgroundImage()"
    CompilerEndIf
EndProcedure


CreateImage(1,25,25,24)
If StartDrawing(ImageOutput(1))
    Box(0,0,OutputWidth()  ,OutputHeight()  ,RGB(0,0,0))
    Box(2,2,OutputWidth()-4,OutputHeight()-4,RGB(64,64,64))
    StopDrawing()
EndIf

CreateImage(2,50,50,24)
If StartDrawing(ImageOutput(2))
        For i = 0 To 50 Step 10
            Box(0,i  ,OutputWidth(),5,RGB(180,180,180))
            Box(0,i+5,OutputWidth(),5,RGB(192,192,192))
        Next i
    StopDrawing()
EndIf

CreateImage(3,10,10,24)
If StartDrawing(ImageOutput(3))
    Box(0,0,OutputWidth(),OutputHeight(),RGB(192,192,192))
    Box(OutputWidth()-2,OutputHeight()-2,2,2,RGB(64,64,64))
    StopDrawing()
EndIf


If OpenWindow(1,0,0,800,600,"Window Background Image",#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Invisible)

    SetWindowBackgroundPattern(1,ImageID(3))
    
    For i = 1 To 10
        ButtonGadget(#PB_Any, 25, 10+i*30, 150, 25, "Button "+Str(i))
    Next i
    
    
    OpenWindow(2,WindowX(1)+WindowWidth(1)-100,WindowY(1)+100,200,150,"Tool Window 1",#PB_Window_Tool|#PB_Window_SizeGadget|#PB_Window_Invisible,WindowID(1))    
    SetWindowBackgroundPattern(2,ImageID(2))
    ButtonGadget(#PB_Any,10,10,180,25,"Button")
    
    OpenWindow(3,WindowX(1)+WindowWidth(1)-150,WindowY(1)+300,300,150,"Tool Window 2",#PB_Window_Tool|#PB_Window_SizeGadget|#PB_Window_Invisible,WindowID(1))    
    SetWindowBackgroundPattern(3,ImageID(1))
    ButtonGadget(#PB_Any,10,10,180,25,"Button")
    
    
    HideWindow(1,0)
    HideWindow(2,0)
    HideWindow(3,0)
    
    
    Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf
Works fine with fixed size windows, but on MacOSX the background is scrolling
when you resize the window. It happens because the pattern drawing begins
at the bottom of the window.

Thought now using a container could fix this, but it doesn't. Even more weird,
the container background pattern scrolls just by resizing the window, not
the container itself!

Code: Select all

Procedure SetContainerBackgroundPattern(containerGadget,imageID)
        CocoaMessage(@color,0,"NSColor colorWithPatternImage:",imageID)
        If color
            CocoaMessage(0,GadgetID(containerGadget),"setFillColor:",color)
            ProcedureReturn color
        EndIf
EndProcedure


CreateImage(1,25,25,24)
If StartDrawing(ImageOutput(1))
    Box(0,0,OutputWidth()  ,OutputHeight()  ,RGB(0,0,0))
    Box(2,2,OutputWidth()-4,OutputHeight()-4,RGB(64,64,64))
    StopDrawing()
EndIf

CreateImage(2,50,50,24)
If StartDrawing(ImageOutput(2))
        For i = 0 To 50 Step 10
            Box(0,i  ,OutputWidth(),5,RGB(180,180,180))
            Box(0,i+5,OutputWidth(),5,RGB(192,192,192))
        Next i
    StopDrawing()
EndIf

CreateImage(3,10,10,24)
If StartDrawing(ImageOutput(3))
    Box(0,0,OutputWidth(),OutputHeight(),RGB(192,192,192))
    Box(OutputWidth()-2,OutputHeight()-2,2,2,RGB(64,64,64))
    StopDrawing()
EndIf


If OpenWindow(1,0,0,800,600,"Window Background Image",#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Invisible)
    c1 = ContainerGadget(#PB_Any,0,0,800,600)
    SetContainerBackgroundPattern(c1,ImageID(3))
    
    For i = 1 To 10
        ButtonGadget(#PB_Any, 25, 10+i*30, 150, 25, "Button "+Str(i))
    Next i
    
    
    OpenWindow(2,WindowX(1)+WindowWidth(1)-100,WindowY(1)+100,200,150,"Tool Window 1",#PB_Window_Tool|#PB_Window_SizeGadget|#PB_Window_Invisible,WindowID(1))    
    c2 = ContainerGadget(#PB_Any,0,0,200,150)
    SetContainerBackgroundPattern(c2,ImageID(2))
    ButtonGadget(#PB_Any,10,10,180,25,"Button")
    
    OpenWindow(3,WindowX(1)+WindowWidth(1)-150,WindowY(1)+300,300,150,"Tool Window 2",#PB_Window_Tool|#PB_Window_SizeGadget|#PB_Window_Invisible,WindowID(1))    
    c3 = ContainerGadget(#PB_Any,0,0,300,150)
    SetContainerBackgroundPattern(c3,ImageID(1))
    ButtonGadget(#PB_Any,10,10,180,25,"Button")
    
    
    HideWindow(1,0)
    HideWindow(2,0)
    HideWindow(3,0)
    
    
    Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf
Nice for fixed windows, but for resize-able windows this is not useable as is.

Re: Image as container background?

Posted: Fri Jan 31, 2014 7:44 am
by Poshu
even with my fixed window, I get some strange results and I've got to shuffle my image to display it in one piece...

Re: Image as container background?

Posted: Fri Jan 31, 2014 8:26 am
by wilbert
Danilo wrote:Thought now using a container could fix this, but it doesn't. Even more weird,
the container background pattern scrolls just by resizing the window, not
the container itself!
The documentation of colorWithPatternImage: states The image is tiled starting at the bottom of the window. The image is not scaled.
Although inconvenient, the behavior as you describe it is to be expected.
Maybe you could use setPatternPhase: from the NSGraphicsContext class.

Re: Image as container background?

Posted: Fri Jan 31, 2014 2:30 pm
by Wolfram
Danilo wrote:
Wolfram wrote:can you also give a example for setCornerRadius:

Code: Select all

  CocoaMessage(0, GadgetID(0), "setBoxType:"   , #NSBoxCustom)
  CocoaMessage(0, GadgetID(0), "setBorderType:", #NSLineBorder)

  radius.f = 20.0
  CocoaMessage(0,GadgetID(0),"setCornerRadius:@",@radius)
Hi Danilo,

can you explain me why there is a @ behind the "setCornerRadius: "?

Thanks

Re: Image as container background?

Posted: Fri Jan 31, 2014 5:18 pm
by Shardik
Wolfram wrote:Hi Danilo,

can you explain me why there is a @ behind the "setCornerRadius: "?

Thanks
Although I am not Danilo, I try to answer your question... :wink:

In his posting [PB Cocoa] Methods, Tips & Tricks wilbert describes the syntax of CocoaMessage() and also states:
wilbert wrote:When non integer values have to be passed, they can be passed by reference by adding a @ after a colon character.
The PureBasic help for CocoaMessage states:
PureBasic help for CocoaMessage wrote:Method$
The method to call on the object, usually followed by a semicolon (':'). If the method needs a structure as parameter, '@' needs to be appended after the semicolon.
So if you pass a parameter which is not an integer variable (in Danilo's example a float variable) you have to use @ after the semicolon of the method name and @ in front of the following variable name.

Re: Image as container background?

Posted: Sat Feb 01, 2014 9:53 pm
by Poshu
wilbert wrote:The documentation of colorWithPatternImage: states The image is tiled starting at the bottom of the window. The image is not scaled.
Although inconvenient, the behavior as you describe it is to be expected.
Maybe you could use setPatternPhase: from the NSGraphicsContext class.
Any additional information on that? I have no clue where to start.

Re: Image as container background?

Posted: Sun Feb 02, 2014 7:04 am
by wilbert
Poshu wrote:Any additional information on that? I have no clue where to start.
I don't get it working that way. An alternative is to change the pattern when the window resizes.
The drawback of this, is that you have to re-set the color of all objects that use the pattern each time the window size changes.

Code: Select all

Global PatternImage.i = CreateImage(#PB_Any, 32, 32, 32, RGB(140, 140, 140))
Global PatternImageAdjusted.i = CopyImage(PatternImage, #PB_Any)

StartDrawing(ImageOutput(PatternImage))
Circle(16, 16, 10, RGB(120, 120, 120))
StopDrawing()


Procedure SizeWindowHandler()
  Protected.i h, w, y
  
  w = EventWindow()
  h = ImageHeight(PatternImage)
  y = WindowHeight(w) % h

  StartDrawing(ImageOutput(PatternImageAdjusted))
  DrawImage(ImageID(PatternImage), 0, -y)
  DrawImage(ImageID(PatternImage), 0, h-y)
  StopDrawing()
  CocoaMessage(0, WindowID(w), "setBackgroundColor:", CocoaMessage(0, 0, "NSColor colorWithPatternImage:", ImageID(PatternImageAdjusted)))
  
EndProcedure


OpenWindow(0, 100, 100, 200, 200, "Resize test", #PB_Window_SizeGadget | #PB_Window_SystemMenu)

BindEvent(#PB_Event_SizeWindow, @SizeWindowHandler())
SizeWindowHandler()

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow