Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

Enhancement for non-modal dialogs

#22

As submitted by Joel VanderWerf:

I had to convert some modal dialogs to non-modal, and I abstracted out some of what I was doing. The result is a mixin that uses closures to make non-modal dialogs almost as easy to implement as modal ones. It's going into the next release of FoxTails, but since it stands alone and is quite simple, I'm submitting it here. Hope it helps someone.

The key to using this mixin is in the initialization of the main window:

    nonModalButton.connect(SEL_COMMAND) do
      @dialog.execute_nonmodal do |accepted|
        @label.text = accepted ? "Dialog accepted" : "Dialog cancelled"
      end
    end

The code block is saved away and called later when the dialog is exited. But since it's closure, you can operate on local vars, etc. to apply the result of the dialog. Normally, the way non-modal dialogs interact with their callers is much more awkward than in the modal case, AFAICT.

require 'fox'
require 'fox/responder'

include Fox

module FoxTails
  # Module to include in FXDialogBox to provide an easy nonmodal version
  # of execute.
  module FTNonModal
    include Responder

    def initialize(*args)
      super if defined?(super)
      FXMAPFUNC(SEL_COMMAND, FXDialogBox::ID_CANCEL, :onCmdCancel)
      FXMAPFUNC(SEL_COMMAND, FXDialogBox::ID_ACCEPT, :onCmdAccept)
    end

    # Creates and shows the dialog, and registers the associated block to be
    # called when the dialog is closed. The block is passed a boolean argument
    # which is true if and only if the dialog was accepted.
    def execute_nonmodal(placement = PLACEMENT_CURSOR, &block)
      @__FTNonModal_block = block
      create
      show placement
   end

    def onCmdCancel(*args) # :nodoc:
      on_nonmodal_close(false)
    end

    def onCmdAccept(*args) # :nodoc:
      on_nonmodal_close(true)
    end

    # Called when dialog is closed, with _accepted_ equal to true if and only if
    # the user accepted the dialog.
    def on_nonmodal_close(accepted)
      @__FTNonModal_block[accepted]

      ##return 0 -- why isn't this enough to close window?
      ## oh well, let's immitate FXTopWindow:
      getApp().stopModal(self, accepted ? 1 : 0)
      hide()
    end
  end
end

class TestDialog < FXDialogBox
  include FoxTails::FTNonModal

  def initialize(*args)
    super

    buttons = FXHorizontalFrame.new(self,
      LAYOUT_SIDE_BOTTOM|FRAME_NONE|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH)

    FXButton.new(buttons, "&Accept", nil, self, ID_ACCEPT,
      FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y)

    FXButton.new(buttons, "&Cancel", nil, self, ID_CANCEL,
      FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
  end
end

class MainWindow < FXMainWindow
  def initialize(app)
    super(app, "NonModal test", nil, nil, DECOR_ALL)

    frame = FXHorizontalFrame.new(self)

    nonModalButton = FXButton.new(frame, "&Non-Modal Dialog...", nil, nil, 0,
      FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_X|LAYOUT_CENTER_Y)

    nonModalButton.connect(SEL_COMMAND) do
      @dialog.execute_nonmodal do |accepted|
        @label.text = accepted ? "Dialog accepted" : "Dialog cancelled"
      end
    end

    @label = FXLabel.new(frame, "Dialog not invoked yet")

    @dialog = TestDialog.new(getApp(), "NonModal Dialog",
      DECOR_TITLE|DECOR_BORDER)

    show
  end

end

if __FILE__ == $0
  application = FXApp.new("NonModal", "FoxTailsTest")
  window = MainWindow.new(application)
  application.create
  application.run
end

Reported by lyle (at lylejohnson) · November 11th, 2009 @ 10:14 PM

State: new
Milestone: none
Assigned to: lyle (at lylejohnson) lyle (at lylejohnson)

Activity

No comments yet.

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.