###################################
#
# vrdialog.rb
# Programmed by  nyasu <nyasu@osk.3web.ne.jp>
# Copyright 1999-2001 Nishikawa,Yasuhiro
#
# More information at http://www.threeweb.ad.jp/~nyasu/software/vrproject.html
# (in Japanese)
#
###################################

=begin
= VisualuRuby(tmp) Dialog boxes
=end


vr_DIR="vr/" unless vr_DIR
require vr_DIR+'vruby'
require vr_DIR+'vrcontrol'

class VRDialogTemplate
=begin
== VRDialogTemplate
Create Dialog template string for the argument of 
DialogBoxIndirectParam() Win32API.

=== Attributes
((|style|)),((|exstyle|)),((|caption|)),((|fontsize|)),((|fontname|)) are 
read/write accessible.
((|x|)),((|y|)),((|w|)),((|h|)) are read-only and access these attributes
with 'move' method.

=== Methods
--- move(x,y,w,h)
    Sets the dialog dimension and position. The position is relative from 
    parent window.
--- addDlgControl(ctype,caption,x,y,w,h,style=0)
    Adds a control on the dialog. ((|ctype|)) is the control-class such as 
    VRButton.
--- to_template
    Create a dialog template string and return it.
=end

  attr_accessor :style
  attr_accessor :exstyle
  attr_reader :x
  attr_reader :y
  attr_reader :w
  attr_reader :h
  attr_accessor :caption
  attr_accessor :fontsize
  attr_accessor :fontname

  require 'Win32API'
  MultiByteToWideChar = 
     Win32API.new("kernel32","MultiByteToWideChar",["I","I","P","I","P","I"],"I")

 private
  def padding_dwordAlignment(str)
    a=str.length
    c = ( (a+3)&0xfffc ) - a  # Don't use String whose length is over 0xfffc :)
    str << " "*c
  end

  def mb2wc(str)
    r=" "*(str.length*2)
    l=MultiByteToWideChar.call(0,0,str,str.length,r,r.length)
    r
  end

  def class2param(cls)
    if cls == VRButton then 
      [0xffff,0x80].pack("SS")
    elsif cls == VREdit || cls == VRText
      [0xffff,0x81].pack("SS")
    elsif cls == VRStatic
      [0xffff,0x82].pack("SS")
    elsif cls == VRListbox
      [0xffff,0x83].pack("SS")
    elsif cls == VRScrollbar
      [0xffff,0x84].pack("SS")
    elsif cls == VRCombobox
      [0xffff,0x85].pack("SS")
    else
      mb2wc(cls.Controltype[0]+"\0")
    end
  end

  def tmplateinit
    @_vr_dcontrols={}; @_vr_cid=0; 
    @style = 0x90c800c0
    @exstyle=0
    self.move 100,100,200,100
    @caption=""
    @fontname="system"
    @fontsize=10
  end

  def initialize
    tmplateinit
  end

 public 
  def move(x,y,w,h)
    @x,@y,@w,@h = x,y,w,h
  end
  
  def addDlgControl(ctype,caption,x,y,w,h,style=0)
    newid = @_vr_cid + $VRCONTROL_STARTID*2
    @_vr_dcontrols[newid] = 
            [ctype,"",caption,x,y,w,h,
             ctype.Controltype[1] | style | 0x50000000]  #WS_VISIBLECHILD
    @_vr_cid+=1
    return newid
  end
  
  
  def to_template
    tmp = 
      [
        @style,@exstyle,@_vr_dcontrols.size,@x,@y,@w,@h,0,0
      ] .pack("IISSSSSSS") + mb2wc(@caption+"\0")

    if (@style & 0x40)>0 then # DS_SETFONT
      tmp << [@fontsize].pack("S") << mb2wc(@fontname+"\0")
    end
    padding_dwordAlignment(tmp)

    @_vr_dcontrols.each do |iid,val|
      tmp << [val[7],0,val[3,4],iid].flatten.pack("IISSSSS")
      tmp << class2param(val[0])
      tmp << mb2wc(val[2]+"\0") << [0].pack("S")
      padding_dwordAlignment(tmp)
    end
    return tmp
  end
end


module WMsg
  WM_INITDIALOG = 0x110
end

class VRDialogComponent < SWin::Dialog
  def vrinit
    extend VRWinComponent::VRInitBlocker
  end

  def setscreen(scr)
    @screen=scr
  end
  def create(*arg)
    self.open(*arg)
  end

  def centering(target = @parent) #contributed by Yuya-san./modified by nyasu.
    unless target.is_a?(SWin::Window) then
      target = @screen
    end
    raise "No specified centering target" unless target

    x = target.x + target.w / 2 - self.w / 2
    y = target.y + target.h / 2 - self.h / 2
    self.move(x, y, self.w, self.h)
  end

end

class VRModalDialog <VRDialogComponent
=begin
== VRModalDialog
This class represents a modal dialog.
When a modal dialog opens, the sequence is blocked until the dialog is closed.
(Process about the dialog is advancing.)
VRModalDialog#open method returns the value which is the argument 
at VRModalDialog#close(value). <- SWin::Dialog#close

=== Attributes
Hash of ((|options|)) set values as 'options["cancelbutton"]=canbtn'

=== Class Methods
--- new(screen,template)
    Creates a modal dialog according to ((|template|)) on ((|screen|)).
    ((|screen|)) is usualy VRLocalScreen.
--- new2(screen)
    This yields options (attributes) as Hash and template as VRDialogTemplate.
    You can add some controls or set attributes about the template.
    ((% 
    VRModalDialog.new2(screen) do |options,template| template.addDlgControl...
    %))

=== Methods
--- open(parent)
    See SWin::Dialog#open
--- close(value)
    See SWin::Dialog#close
=end

  include VRParent

  attr :options,1  #hash

  def initialize(*arg)
    @options=[]
  end

  def VRModalDialog.new(screen,template)
    r=screen.factory.newdialog(template.to_template,self)
    r.parentinit(screen)
    r.options={}
    r.addEvent WMsg::WM_INITDIALOG 
    r.addEvent WMsg::WM_COMMAND
    return r
  end

  def VRModalDialog.new2(screen)
    template = VRDialogTemplate.new
    opt={}
    yield(opt,template)
    r=self.new(screen,template)
    r.options=opt if opt.is_a?(Hash)
    return r
  end

  def vrinit
    super
  end

  module VRInitDialogHandler
    def vrinit
      if self.kind_of?(VRMessageHandler) then
        addHandler WMsg::WM_INITDIALOG,"initdialog",MSGTYPE::ARGINTINT,nil
      end
      super
    end

    def msghandler(msg)
      if msg.msg==WMsg::WM_INITDIALOG then
        self.vrinit
        self.construct
      end
      super
    end
  end

  def open(parent)
    @parent=parent
    super
  end
end

class VRScreen
=begin
== VRScreen (additional)
A method is added for dialogs.

=== Method
--- modalform(parent,style=nil,mod=VRModalDialog)
    Creates modal dialogbox whose parent is ((|parent|)).
    ((|mod|)) may be a module or a class which is a descendant of SWin::Dialog.
=end

  PlaneDialogForm = VRDialogTemplate.new.to_template

  def modalform(parent,style=nil,mod=VRModalDialog)
    if mod.is_a?(Class) and mod.ancestors.index(VRModalDialog) then
      frm=@factory.newdialog(PlaneDialogForm,mod)
    elsif mod.is_a?(Module) then
      frm=@factory.newdialog(PlaneDialogForm,VRModalDialog)
      frm.extend mod
    else
      raise ArgError,"a Class/Module of VRModalDialog required"
    end
    frm.parentinit(self)
    frm.addEvent WMsg::WM_INITDIALOG
    frm.extend(VRStdControlContainer)
    frm.style=style if style
    frm.extend(VRModalDialog::VRInitDialogHandler)
    frm.open(parent)
  end
end

class VRInputbox < VRModalDialog
=begin
== VRInputbox
Abstract class of Inputbox.
Ok button, Cancel button and input area are have to be added by addDlgControl.
After creating them, set the options "okbutton","cancelbutton","target" and
"default".
=end
  def msghandler(msg)
    if msg.msg == WMsg::WM_INITDIALOG then
      self.setItemTextOf(@options["target"],@options["default"].to_s)
    end

    if msg.msg == WMsg::WM_COMMAND then
      if msg.wParam==@options["okbutton"] then
        close self.getItemTextOf(@options["target"])
      elsif msg.wParam==@options["cancelbutton"] then
        close false
      end
    end
  end

end

