It is currently Tue Sep 17, 2019 7:56 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: Module OSX Helper for Observer and Methods
PostPosted: Sat Apr 13, 2019 9:13 pm 
Offline
Addict
Addict
User avatar

Joined: Fri May 12, 2006 6:51 pm
Posts: 1902
Location: Germany
There are always nice examples of how to work with observer and methods.
I wanted to simplify that a bit.

I don't know which methods can be added to a gadget. Removing a single method is not possible without further ado.
Code:
;-TOP
; Comment : osx Helper
; Author  : mk-soft
; Version : v1.01
; Create  : 13.04.2019
; Update  :
; OS      : macOS

;- Begin Module

DeclareModule osxClassHelper
  ; Create a new class with NSObject and Method
  Declare CreateClass(ClassName.s, RegisterName.s, *Callback, Args.s) ; Result Object (Instance)
  Declare DisposeClass(ClassName.s)
 
  ; Add Method to Gadget
  Declare AddGadgetMethod(Gadget, RegisterName.s, *Callback, Args.s) ; True or False
  Declare DisposeGadgetMethods(Gadget)
 
EndDeclareModule

; ---

Module osxClassHelper
 
  EnableExplicit
 
  ImportC ""
    objc_disposeClassPair(*Class)
  EndImport
 
  ;-- Structure
 
  Structure udtClassObject
    *Class
    *Object
  EndStructure
 
  Structure udtMethodList
    Name.s
    *Method
  EndStructure
 
  Structure udtGadgetObject
    *GadgetID
    *OldGadgetClass
    *NewGadgetClass
    Map MethodList.udtMethodList()
  EndStructure
 
  ;-- Globals
 
  Global NewMap ClassObject.udtClassObject()
  Global NewMap GadgetObject.udtGadgetObject()
 
  ;- New Object with instance
 
  Procedure CreateClass(ClassName.s, RegisterName.s, *Callback, Args.s)
    Protected *Class, *Method, *Object
    *Class = objc_allocateClassPair_(objc_getClass_("NSObject"), ClassName, 0)
    If Not *Class
      ProcedureReturn 0
    EndIf
    *Method = class_addMethod_(*Class, sel_registerName_(RegisterName), *Callback, Args)
    If Not *Method
      objc_disposeClassPair(*Class)
      ProcedureReturn 0
    EndIf
    If Not objc_registerClassPair_(*Class)
      objc_disposeClassPair(*Class)
      ProcedureReturn 0
    EndIf
    *Object = CocoaMessage(0, 0, ClassName + " new")
    If Not *Object
      objc_disposeClassPair(*Class)
      ProcedureReturn 0
    EndIf
    ClassObject(ClassName)\Class = *Class
    ClassObject()\Object = *Object
    ProcedureReturn *Object
  EndProcedure
 
  Procedure DisposeClass(ClassName.s)
    If FindMapElement(ClassObject(), ClassName)
      CocoaMessage(0, ClassObject()\Object, "release")
      objc_disposeClassPair(ClassObject()\Class)
      DeleteMapElement(ClassObject())
    EndIf
  EndProcedure
 
  ;- Add Method to Gadget
 
  Procedure AddGadgetMethod(Gadget, RegisterName.s, *Callback, Args.s)
   
    With GadgetObject()
      If Not FindMapElement(GadgetObject(), Hex(Gadget))
        AddMapElement(GadgetObject(), Hex(Gadget))
        \GadgetID = GadgetID(Gadget)
        \OldGadgetClass = CocoaMessage(0, GadgetID(Gadget), "class")
        \NewGadgetClass = objc_allocateClassPair_(\OldGadgetClass, "classGadget_" + \GadgetID, 0)
        If Not \NewGadgetClass
          ProcedureReturn 0
        EndIf
        objc_registerClassPair_(\NewGadgetClass)
        object_setClass_(\GadgetID, \NewGadgetClass)
      EndIf
      If Not FindMapElement(\MethodList(), RegisterName)
        AddMapElement(\MethodList(), RegisterName)
        \MethodList()\Name = RegisterName
        \MethodList()\Method = class_addMethod_(\NewGadgetClass, sel_registerName_(RegisterName), *Callback, Args)
        If Not \MethodList()\Method
          DeleteMapElement(\MethodList())
          If MapSize(\MethodList()) = 0
            object_setClass_(\GadgetID, \OldGadgetClass)
            objc_disposeClassPair(\NewGadgetClass)
            DeleteMapElement(GadgetObject())
          EndIf
          ProcedureReturn 0
        EndIf
      EndIf
      ProcedureReturn \MethodList()\Method
    EndWith
  EndProcedure
 
  Procedure DisposeGadgetMethods(Gadget)
    With GadgetObject()
      If FindMapElement(GadgetObject(), Hex(Gadget))
        object_setClass_(\GadgetID, \OldGadgetClass)
        objc_disposeClassPair(\NewGadgetClass)
        DeleteMapElement(GadgetObject())
      EndIf
    EndWith
  EndProcedure
 
EndModule

;- End Module

CompilerIf #PB_Compiler_IsMainFile
 
  UseModule osxClassHelper
 
  EnumerationBinary
    #NSKeyValueObservingOptionNew
    #NSKeyValueObservingOptionOld
  EndEnumeration
 
  Global *NSKeyValueChangeNewKey.Integer = dlsym_(#RTLD_DEFAULT, "NSKeyValueChangeNewKey")
  Global *NSKeyValueChangeOldKey.Integer = dlsym_(#RTLD_DEFAULT, "NSKeyValueChangeOldKey")
 
  Enumeration #PB_Event_FirstCustomValue
    #EventChangeAppearance
  EndEnumeration
 
  ProcedureC KVO(obj, sel, keyPath, object, change, context)
    Select PeekS(CocoaMessage(0, keyPath, "UTF8String"), -1, #PB_UTF8)
       
      Case "effectiveAppearance":
        CocoaMessage(0, 0, "NSAppearance setCurrentAppearance:", CocoaMessage(0, change, "objectForKey:", *NSKeyValueChangeNewKey\i))
        PostEvent(#EventChangeAppearance)
       
    EndSelect
  EndProcedure
 
  ; Create Key-Value Observer class (PB_KVO)
  KVO = CreateClass("PB_KVO", "observeValueForKeyPath:ofObject:change:context:", @KVO(), "v@:@@@^v")
 
  ; add observer
  Global NSApp.i = CocoaMessage(0, 0, "NSApplication sharedApplication")
  CocoaMessage(0, NSApp, "addObserver:", KVO, "forKeyPath:$", @"effectiveAppearance", "options:", #NSKeyValueObservingOptionNew, "context:", #nil)
 
  ; ---
 
  Procedure NSColorToRGB(NSColor)
    Protected.cgfloat red, green, blue
    Protected r, g, b, a
    Protected nscolorspace, rgb
    nscolorspace = CocoaMessage(0, nscolor, "colorUsingColorSpaceName:$", @"NSCalibratedRGBColorSpace")
    If nscolorspace
      CocoaMessage(@red, nscolorspace, "redComponent")
      CocoaMessage(@green, nscolorspace, "greenComponent")
      CocoaMessage(@blue, nscolorspace, "blueComponent")
      rgb = RGB(red * 255.0, green * 255.0, blue * 255.0)
      ProcedureReturn rgb
    EndIf
  EndProcedure
 
  Procedure NSColorByNameToRGB(NSColorName.s)
    Protected.cgfloat red, green, blue
    Protected r, g, b, a
    Protected nscolorspace, rgb
    nscolorspace = CocoaMessage(0, CocoaMessage(0, 0, "NSColor " + NSColorName), "colorUsingColorSpaceName:$", @"NSCalibratedRGBColorSpace")
    If nscolorspace
      CocoaMessage(@red, nscolorspace, "redComponent")
      CocoaMessage(@green, nscolorspace, "greenComponent")
      CocoaMessage(@blue, nscolorspace, "blueComponent")
      rgb = RGB(red * 255.0, green * 255.0, blue * 255.0)
      ProcedureReturn rgb
    EndIf
  EndProcedure
  ; ---
 
  Global Event, text_color, control_background_color , buttonimage, buttonimage_pressed
 
  Procedure UpdateColors()
    text_color = NSColorByNameToRGB("textColor")
    control_background_color = NSColorByNameToRGB("windowBackgroundColor")
    If StartDrawing(CanvasOutput(0))
      Box(0, 0, OutputWidth(), OutputHeight(), control_background_color)
      DrawingMode(#PB_2DDrawing_Transparent)
      DrawText(10, 10, "Update colors", text_color)
      StopDrawing()
    EndIf
  EndProcedure
 
  ; ---
 
  ProcedureC UpdateLayer(SubclassedButton.I, Selector.I)
    Protected cell.i, layer.i, image.i
    Protected Rect.CGRect
   
    cell = CocoaMessage(0, SubclassedButton, "cell")
    layer = CocoaMessage(0, SubclassedButton, "layer", 0 )
    If CocoaMessage(0, cell, "isHighlighted")
      ;image =CocoaMessage(0, 0, "NSImage imageNamed:$", @"button_pressed.png")
      CocoaMessage(0, layer, "setContents:", buttonimage_pressed)
    Else
      ;image =CocoaMessage(0, 0, "NSImage imageNamed:$", @"button.png")
      CocoaMessage(0, layer, "setContents:", buttonimage)
      CocoaMessage(@Rect, layer, "contentsCenter")
      Rect\origin\x  =0.5
      Rect\origin\y =0.5
      Rect\size\width =0
      Rect\size\height =0
      CocoaMessage(0, layer, "setContentsCenter:@", @Rect)
    EndIf
  EndProcedure
 
  ; ---
 
  buttonimage = CreateImage(0, 140, 30, 32, $FF901E)
  buttonimage_pressed = CreateImage(1, 140, 30, 32, $CD7418)
 
  OpenWindow(0, #PB_Ignore, #PB_Ignore, 300, 150, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
 
  CanvasGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20, #PB_Canvas_Container)
  ButtonGadget(1, 70, 40, 140, 30, "Click me!")
  SetGadgetFont(1, LoadFont(0, "Apple Chancery", 18))
  CloseGadgetList()
 
  CocoaMessage(0, GadgetID(1), "setWantsLayer:", #YES)
  AddGadgetMethod(1, "updateLayer", @UpdateLayer(), "v@")
 
  UpdateColors()
 
  Repeat
    Event = WaitWindowEvent()
    If Event = #EventChangeAppearance
      UpdateColors()
    EndIf
  Until Event = #PB_Event_CloseWindow
 
  ; remove observer
 
  CocoaMessage(0, NSApp, "removeObserver:", KVO, "forKeyPath:$", @"effectiveAppearance")
  DisposeClass("PB_KVO")
  DisposeGadgetMethods(1)
 
CompilerEndIf

_________________
My Projects ThreadToGUI / OOP-BaseClass / OOP-BaseClassDispatch / EventDesigner V3
PB v3.30 / v5.70 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye