Problem with sheet Alert

Mac OSX specific forum
Wolfram
Enthusiast
Enthusiast
Posts: 568
Joined: Thu May 30, 2013 4:39 pm

Problem with sheet Alert

Post by Wolfram »

I use a sheet modal Alert, but the menu events are still fired.
How can i make it work like a normal Alert which blocks all events?

Code: Select all

; NSBlock module by Wilbert
; last update July 17, 2015

DeclareModule NSBlock
  
  Structure NSBlock
    *isa
    flags.l
    reserved.l
    *invoke
    *descriptor
  EndStructure
  
  Structure NSBlockWithPtr
    *block.NSBlock
    _block.NSBlock
  EndStructure
  
  Declare InitNSBlockWithPtr(*NSBlockWithPtr.NSBlockWithPtr, *Invoke, IsGlobal = #True)
  
EndDeclareModule

Module NSBlock
  
  Global.i NSConcreteGlobalBlock, NSConcreteStackBlock, DyLib
  
  DyLib = OpenLibrary(#PB_Any, "libSystem.dylib")
  If DyLib
    NSConcreteGlobalBlock = GetFunction(DyLib, "_NSConcreteGlobalBlock")
    NSConcreteStackBlock = GetFunction(DyLib, "_NSConcreteStackBlock")    
    CloseLibrary(DyLib)
  EndIf
  
  If Not NSConcreteGlobalBlock
    MessageRequester("Error", "Unable to access _NSConcreteGlobalBlock symbol")
    End
  EndIf
  
  DataSection
    NSBlockDescriptor:
    Data.i 0, SizeOf(NSBlock), 0, 0
  EndDataSection
  
  Procedure InitNSBlockWithPtr(*NSBlockWithPtr.NSBlockWithPtr, *Invoke, IsGlobal = #True)
    *NSBlockWithPtr\block = @*NSBlockWithPtr\_block
    With *NSBlockWithPtr\_block
      If IsGlobal
        \isa = NSConcreteGlobalBlock
        \flags = $30000000
      Else
        \isa = NSConcreteStackBlock
        \flags = $20000000
      EndIf
      \invoke = *Invoke
      \descriptor = ?NSBlockDescriptor
    EndWith
  EndProcedure
  
EndModule

; *** End of NSBlock module ***


UseModule NSBlock

#NSCriticalAlertStyle = 2
#NSInformationalAlertStyle = 1 
#NSWarningAlertStyle = 0

Enumeration NSAlertButton
  #firstButton =1000
  #secondButton
EndEnumeration


#NSCommandKeyMask    = 1 << 20

Global MyBlockWithPtr.NSBlockWithPtr


;//Custom Icon for Alert
Global myIcon = CreateImage(#PB_Any, 64, 64, 32, $FFF26A0B)

Global mainWindow, button


ProcedureC ModalSheetCallback(*Block.NSBlock, returnCode)
 


  Select returnCode
    Case #firstButton
      Debug "OK"
      
    Case #secondButton
      Debug "Not OK"
      
  EndSelect

EndProcedure


InitNSBlockWithPtr(@MyBlockWithPtr, @ModalSheetCallback())



Procedure sheetAlert(message.s = "", informativeText.s= "", hasAccessory = #NO, icon = #Null)
  
 
    NSAlert = CocoaMessage(0,CocoaMessage(0, 0, "NSAlert alloc"), "init")
    
    CocoaMessage(0, NSAlert, "setMessageText:$", @message)
    CocoaMessage(0, NSAlert, "setInformativeText:$", @informativeText)
    
    
    defaultButton =CocoaMessage(0, NSAlert, "addButtonWithTitle:$", @"OK")
    
    noButton =CocoaMessage(0, NSAlert, "addButtonWithTitle:$", @"not OK")
    CocoaMessage(0, noButton, "setKeyEquivalent:$", @"n")
    CocoaMessage(0, noButton, "setKeyEquivalentModifierMask:", #NSCommandKeyMask)
    
    
    CocoaMessage(0, NSAlert, "setAlertStyle:", #NSInformationalAlertStyle)
    
    If icon
      CocoaMessage(0, NSAlert, "setIcon:", ImageID(icon))
    EndIf
    

    
    If hasAccessory
      strGadget = StringGadget(#PB_Any, 20, 68, 327, 20, "...you answare")
      
      strGadgetID = GadgetID(strGadget)
      CocoaMessage(0, NSAlert, "setAccessoryView:", strGadgetID)
      
      
      CocoaMessage(0, strGadgetID, "currentEditor")
      
      ;//Set defaultButton action while StringGadget has focus
      CocoaMessage(0, strGadgetID, "setTarget:", defaultButton)
      CocoaMessage(0, strGadgetID, "setAction:", sel_registerName_("performClick:"))
      
      CocoaMessage(0, NSAlert, "layout")
      
      CocoaMessage(0, strGadgetID, "becomeFirstResponder")

      
    EndIf
    
    CocoaMessage(0, NSAlert, "beginSheetModalForWindow:", WindowID(mainWindow), "completionHandler:@", @MyBlockWithPtr)

EndProcedure


Procedure mainWindowEvents(event)
  
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False
      
    Case #PB_Event_Menu
      Debug "Menu is triggert"
      Select EventMenu()
          
          
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case button
          sheetAlert("My Alert", "Global warming", #YES, myIcon)
          
        Case strGadget
          If EventType() = #PB_EventType_Change
            Debug GetGadgetText(strGadget)
          EndIf
          
      EndSelect
  EndSelect
  
  ProcedureReturn #True
EndProcedure




mainWindow = OpenWindow(#PB_Any, 0, 0, 400, 120, "MAIN WINDOW", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
button = ButtonGadget(#PB_Any, 150, 30, 90, 25, "show Alert")

If CreateMenu(0, WindowID(mainWindow))
  MenuTitle("TestMenu")
  MenuItem(0, "Open..."   +#TAB$+"Cmd+O")
EndIf


Repeat
  event = WaitWindowEvent()
Until mainWindowEvents(event) = #False
macOS Catalina 10.15.7
Wolfram
Enthusiast
Enthusiast
Posts: 568
Joined: Thu May 30, 2013 4:39 pm

Re: Problem with sheet Alert

Post by Wolfram »

I put a loop with WaitWindowEvent() inside the sheetRequester().
Normale you should use only one event loop, but in this case it seams to be ok.

Can someone verify it?

Code: Select all

; NSBlock module by Wilbert
; last update July 17, 2015

DeclareModule NSBlock
  #waitForRequest = 0
  Global sheetResult
  
  Structure NSBlock
    *isa
    flags.l
    reserved.l
    *invoke
    *descriptor
  EndStructure
  
  Structure NSBlockWithPtr
    *block.NSBlock
    _block.NSBlock
  EndStructure
  
  Declare InitNSBlockWithPtr(*NSBlockWithPtr.NSBlockWithPtr, *Invoke, IsGlobal = #True)
  
EndDeclareModule


Module NSBlock
  
  Global.i NSConcreteGlobalBlock, NSConcreteStackBlock
  Define DyLib
  
  DyLib = OpenLibrary(#PB_Any, "libSystem.dylib")
  If DyLib
    NSConcreteGlobalBlock = GetFunction(DyLib, "_NSConcreteGlobalBlock")
    NSConcreteStackBlock = GetFunction(DyLib, "_NSConcreteStackBlock")    
    CloseLibrary(DyLib)
  EndIf
  
  If Not NSConcreteGlobalBlock
    MessageRequester("Error", "Unable to access _NSConcreteGlobalBlock symbol")
    End
  EndIf
  
  DataSection
    NSBlockDescriptor:
    Data.i 0, SizeOf(NSBlock), 0, 0
  EndDataSection
  
  Procedure InitNSBlockWithPtr(*NSBlockWithPtr.NSBlockWithPtr, *Invoke, IsGlobal = #True)
    *NSBlockWithPtr\block = @*NSBlockWithPtr\_block
    With *NSBlockWithPtr\_block
      If IsGlobal
        \isa = NSConcreteGlobalBlock
        \flags = $30000000
      Else
        \isa = NSConcreteStackBlock
        \flags = $20000000
      EndIf
      \invoke = *Invoke
      \descriptor = ?NSBlockDescriptor
    EndWith
  EndProcedure
  
EndModule

; *** End of NSBlock module ***


UseModule NSBlock

#NSCriticalAlertStyle = 2
#NSInformationalAlertStyle = 1 
#NSWarningAlertStyle = 0

Enumeration NSAlertButton
  #firstButton =1000
  #secondButton
  #thirdButton
EndEnumeration


#NSCommandKeyMask    = 1 << 20

Global MyBlockWithPtr.NSBlockWithPtr


Global mainWindow, button


ProcedureC sheetChannleCallback(*Block.NSBlock, returnCode)
  
  NSBlock::sheetResult = returnCode
EndProcedure


InitNSBlockWithPtr(@MyBlockWithPtr, @sheetChannleCallback())


Procedure sheetRequester(message.s = "", informativeText.s= "")
  
  Protected NSAlert
  Protected defaultButton, buttonNo, buttonElse
  sheetResult = #waitForRequest
  
  NSAlert = CocoaMessage(0, CocoaMessage(0, 0, "NSAlert alloc"), "init")
  CocoaMessage(0, NSAlert, "setMessageText:$", @message)
  CocoaMessage(0, NSAlert, "setInformativeText:$", @informativeText)
  
  
  defaultButton =CocoaMessage(0, NSAlert, "addButtonWithTitle:$", @"Yes")
  
  
  buttonNo =CocoaMessage(0, NSAlert, "addButtonWithTitle:$", @"No")
  Protected frame.CGPoint
  CocoaMessage(@frame, buttonNo, "frame", 0)
  frame\x -28
  CocoaMessage(0, buttonNo, "setFrame:@", @frame)
  CocoaMessage(0, buttonNo, "setKeyEquivalent:$", @"n")
  
  
  
  buttonElse =CocoaMessage(0, NSAlert, "addButtonWithTitle:$", @"Else")
  CocoaMessage(0, buttonElse, "setKeyEquivalent:$", @"e")
  
  
  CocoaMessage(0, NSAlert, "setAlertStyle:", #NSInformationalAlertStyle)
  
  
  CocoaMessage(0, NSAlert, "layout")
  
  
  CocoaMessage(0, NSAlert, "beginSheetModalForWindow:", WindowID(mainWindow), "completionHandler:@", @MyBlockWithPtr)
  
  
  Repeat
    WaitWindowEvent()
  Until sheetResult <> #waitForRequest
  
  ProcedureReturn sheetResult
EndProcedure


Procedure mainWindowEvents(event)
  
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False
      
    Case #PB_Event_Menu
      Debug "Menu is triggert"
      Select EventMenu()
             
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case button
          result = sheetChanaleRequester("Massage", "Please make your choice...")
          Select result
            Case #firstButton
              Debug "Yes"
            Case #secondButton
              Debug "No"
            Case #thirdButton
              Debug "Else"
          EndSelect
          
      EndSelect
  EndSelect
  
  ProcedureReturn #True
EndProcedure



mainWindow = OpenWindow(#PB_Any, 0, 0, 400, 120, "MAIN WINDOW", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
button = ButtonGadget(#PB_Any, 150, 30, 90, 25, "show Alert")

If CreateMenu(0, WindowID(mainWindow))
  MenuTitle("TestMenu")
  MenuItem(0, "Open..."   +#TAB$+"Cmd+O")
EndIf


Repeat
  event = WaitWindowEvent()
Until mainWindowEvents(event) = #False
macOS Catalina 10.15.7
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Problem with sheet Alert

Post by wilbert »

Wolfram wrote:I use a sheet modal Alert, but the menu events are still fired.
How can i make it work like a normal Alert which blocks all events?
I think it has to do with sheet modal.
If you use "runModal" instead, menu events are ignored but that way the alert box is not attached to the window.
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply