fzeet 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,32 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ window.menu = Menu.new.
7
+ append(:popup, '&Go To', PopupMenu.new.
8
+ append(:string, '&Back', :back).
9
+ append(:string, '&Forward', :forward).
10
+ append(:string, '&Up', :up)
11
+ )
12
+
13
+ (browser = ExplorerBrowser.new(window)).
14
+ SetOptions(Windows::EBO_SHOWFRAMES)
15
+
16
+ def (browser.events).OnNavigationComplete(pidl)
17
+ FFI::MemoryPointer.new(:char, 4096) { |p|
18
+ Windows.SHGetPathFromIDList(pidl, p)
19
+
20
+ message p.read_string
21
+ }
22
+
23
+ Windows::S_OK
24
+ end
25
+
26
+ browser.goto(:Desktop)
27
+
28
+ window.
29
+ on(:command, :back, &browser.method(:back)).
30
+ on(:command, :forward, &browser.method(:forward)).
31
+ on(:command, :up, &browser.method(:up))
32
+ }
@@ -0,0 +1,33 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ window.menu = Menu.new.
7
+ append(:popup, '&View', PopupMenu.new.
8
+ append(:string, '&Refresh', :refresh)
9
+ ).
10
+
11
+ append(:popup, '&Go To', PopupMenu.new.
12
+ append(:string, '&Back', :back).
13
+ append(:string, '&Forward', :forward).
14
+ append(:string, '&Home', :home).
15
+ append(:string, '&Search', :search)
16
+ )
17
+
18
+ browser = WebBrowser.new(window)
19
+
20
+ def (browser.events).NavigateComplete(url)
21
+ message Windows.WCSTOMBS(url)
22
+ end
23
+
24
+ browser.search
25
+
26
+ window.
27
+ on(:command, :refresh, &browser.method(:refresh)).
28
+
29
+ on(:command, :back, &browser.method(:back)).
30
+ on(:command, :forward, &browser.method(:forward)).
31
+ on(:command, :home, &browser.method(:home)).
32
+ on(:command, :search, &browser.method(:search))
33
+ }
@@ -24,7 +24,9 @@ Application.run { |window|
24
24
  }.
25
25
 
26
26
  on(:command, :openMultiple) {
27
- FileOpenDialog.new(flags: :allowmultiselect) { |dialog|
27
+ FileOpenDialog.new { |dialog|
28
+ dialog.multiselect = true
29
+
28
30
  message dialog.paths.join("\n") if dialog.show.ok?
29
31
  }
30
32
  }.
data/examples/MDI.rbw CHANGED
@@ -3,28 +3,130 @@ require 'fzeet'
3
3
  include Fzeet
4
4
 
5
5
  Application.run(Frame.new) { |window|
6
- children, total = [], 0
7
-
8
6
  window.menu.
9
7
  append(:popup, '&File', PopupMenu.new.
10
- append(:string, '&New', :new)
8
+ append(:string, "&New\tCtrl+N", :new).
9
+ append(:string, "&Open...\tCtrl+O", :open).
10
+ append(:string, "&Save\tCtrl+S", :save).
11
+ append(:string, "Save &As...\tCtrl+Shift+S", :saveAs)
11
12
  )
12
13
 
14
+ Application.accelerators << AcceleratorTable.new(
15
+ [:control, :n, :new],
16
+ [:control, :o, :open],
17
+ [:control, :s, :save],
18
+ [[:control, :shift], :s, :saveAs]
19
+ )
20
+
13
21
  window.
14
22
  on(:command, :new) {
15
- children << MDIChild.new(window.client, caption: "Child#{total += 1}").
16
- on(:close) { |args|
17
- args[:result] = nil if args[:sender].question('Close?', buttons: [:yes, :No]).yes?
18
- }.
23
+ child = MDIChild.new(window.client, caption: 'Untitled')
24
+
25
+ Scintilla.new(child, :sci, style: :border, position: child.rect.to_a, anchor: :ltrb)
26
+
27
+ child[:sci].focus = true
28
+
29
+ child[:sci].font = 'Courier New'
30
+ child[:sci].fontSize = 10
31
+
32
+ child[:sci].tabWidth = 2
33
+
34
+ child.on(:close) { |args|
35
+ if args[:sender][:sci].dirty?
36
+ answer = args[:sender].question(%Q{
37
+ File not saved:
38
+ #{args[:sender].text}
39
+
40
+ Press Yes to save it and close the window
41
+ Press No to close the window without saving
42
+ Press Cancel to leave the window open
43
+ }, buttons: [:yes, :no, :Cancel], icon: :warning)
44
+
45
+ window.sendmsg(:command, Command[:save]) if answer.yes?
46
+
47
+ args[:result] = nil unless answer.cancel?
48
+ else
49
+ args[:result] = nil
50
+ end
51
+ }
52
+ }.
53
+
54
+ on(:command, :open) {
55
+ ((Windows::WINVER.AtLeastWindowsVista?) ? ShellFileOpenDialog : FileOpenDialog).new { |dialog|
56
+ dialog.multiselect = true
57
+
58
+ next unless dialog.show.ok?
59
+
60
+ dialog.paths.each { |path|
61
+ window.sendmsg(:command, Command[:new])
19
62
 
20
- on(:destroy) { |args| children.delete(args[:sender]) }
63
+ child = window.activeChild
64
+
65
+ child.text, child[:sci].text = path, File.read(path)
66
+
67
+ child[:sci].toggle(:dirty).sendmsg(:emptyundobuffer)
68
+ }
69
+ }
70
+ }.
71
+
72
+ on(:command, :saveAs) {
73
+ ((Windows::WINVER.AtLeastWindowsVista?) ? ShellFileSaveDialog : FileSaveDialog).new { |dialog|
74
+ next unless dialog.show.ok?
75
+
76
+ child = window.activeChild
77
+
78
+ File.open(child.text = dialog.path, 'w') { |f| f << child[:sci].text; child[:sci].dirty = false }
79
+ }
80
+ }.
81
+
82
+ on(:command, :save) {
83
+ child = window.activeChild
84
+
85
+ (child.text == 'Untitled') ?
86
+ window.sendmsg(:command, Command[:saveAs]) :
87
+ File.open(child.text, 'w') { |f| f << child[:sci].text; child[:sci].dirty = false }
88
+ }.
89
+
90
+ on(:command, :saveAll) {
91
+ window.client.eachChild { |child|
92
+ next unless child.kind_of?(MDIChild)
93
+
94
+ window.
95
+ activate(child).
96
+ sendmsg(:command, Command[:save])
97
+ }
98
+ }.
99
+
100
+ on(:initmenupopup) {
101
+ child = window.activeChild
102
+
103
+ [:save, :saveAs].each { |command| window.menu[command].enabled = !child.nil? }
21
104
  }.
22
105
 
23
106
  on(:close) {
107
+ dirties = []
108
+
24
109
  window.client.eachChild { |child|
25
- # Ask each child if it's ok to close
110
+ next unless child.kind_of?(MDIChild)
111
+
112
+ dirties << child if child[:sci].dirty?
26
113
  }
27
114
 
28
- window.dispose
115
+ if dirties.length > 0
116
+ answer = window.question(%Q{
117
+ File#{(dirties.length > 1) ? 's' : ''} not saved:
118
+ #{dirties.map(&:text).join("\n ")}
119
+
120
+ Press Yes to save #{(dirties.length > 1) ? 'them' : 'it'} and close the application
121
+ Press No to close the application without saving
122
+ Press Cancel to leave the application open
123
+ }, buttons: [:yes, :no, :Cancel], icon: :warning)
124
+
125
+ window.sendmsg(:command, Command[:saveAll]) if answer.yes?
126
+
127
+ window.dispose unless answer.cancel?
128
+ else
129
+ window.dispose
130
+ end
29
131
  }
30
132
  }
@@ -2,44 +2,44 @@ require 'fzeet'
2
2
 
3
3
  include Fzeet::Windows
4
4
 
5
- def onItem1(*args)
6
- Fzeet.message __method__
5
+ Fzeet::Application.run { |window|
6
+ def onItem1(*args)
7
+ Fzeet.message __method__
7
8
 
8
- UIF.SetUICommandProperty(CmdButton1, UI_PKEY_Enabled, PROPVARIANT[:bool, true])
9
- UIF.SetUICommandProperty(CmdItem1, UI_PKEY_Enabled, PROPVARIANT[:bool, false])
10
- end
9
+ UIF.SetUICommandProperty(CmdButton1, UI_PKEY_Enabled, PROPVARIANT[:bool, true])
10
+ UIF.SetUICommandProperty(CmdItem1, UI_PKEY_Enabled, PROPVARIANT[:bool, false])
11
+ end
11
12
 
12
- def onButton1(*args)
13
- Fzeet.message __method__
13
+ def onButton1(*args)
14
+ Fzeet.message __method__
14
15
 
15
- UIF.SetUICommandProperty(CmdItem1, UI_PKEY_Enabled, PROPVARIANT[:bool, true])
16
- UIF.SetUICommandProperty(CmdButton1, UI_PKEY_Enabled, PROPVARIANT[:bool, false])
17
- end
16
+ UIF.SetUICommandProperty(CmdItem1, UI_PKEY_Enabled, PROPVARIANT[:bool, true])
17
+ UIF.SetUICommandProperty(CmdButton1, UI_PKEY_Enabled, PROPVARIANT[:bool, false])
18
+ end
18
19
 
19
- UICH = UICommandHandler.new
20
+ UICH = UICommandHandler.new
20
21
 
21
- def UICH.Execute(*args)
22
- case args[0]
23
- when CmdItem1
24
- onItem1(*args)
25
- when CmdButton1
26
- onButton1(*args)
27
- end
22
+ def UICH.Execute(*args)
23
+ case args[0]
24
+ when CmdItem1
25
+ onItem1(*args)
26
+ when CmdButton1
27
+ onButton1(*args)
28
+ end
28
29
 
29
- S_OK
30
- end
30
+ S_OK
31
+ end
31
32
 
32
- UIA = UIApplication.new
33
+ UIA = UIApplication.new
33
34
 
34
- def UIA.OnCreateUICommand(*args)
35
- UICH.QueryInterface(UICH.class::IID, args[-1])
35
+ def UIA.OnCreateUICommand(*args)
36
+ UICH.QueryInterface(UICH.class::IID, args[-1])
36
37
 
37
- S_OK
38
- end
38
+ S_OK
39
+ end
39
40
 
40
- UIF = UIFramework.new
41
+ UIF = UIFramework.new
41
42
 
42
- Fzeet::Application.run { |window|
43
43
  UIF.Initialize(window.handle, UIA)
44
44
  UIF.LoadUI(LoadRibbonDll(), "APPLICATION_RIBBON\0".encode('utf-16le'))
45
45
 
@@ -2,32 +2,32 @@ require 'fzeet'
2
2
 
3
3
  include Fzeet::Windows
4
4
 
5
- def onButton1(*args)
6
- Fzeet.message __method__
7
- end
5
+ Fzeet::Application.run { |window|
6
+ def onButton1(*args)
7
+ Fzeet.message __method__
8
+ end
8
9
 
9
- UICH = UICommandHandler.new
10
+ UICH = UICommandHandler.new
10
11
 
11
- def UICH.Execute(*args)
12
- case args[0]
13
- when CmdButton1
14
- onButton1(*args)
15
- end
12
+ def UICH.Execute(*args)
13
+ case args[0]
14
+ when CmdButton1
15
+ onButton1(*args)
16
+ end
16
17
 
17
- S_OK
18
- end
18
+ S_OK
19
+ end
19
20
 
20
- UIA = UIApplication.new
21
+ UIA = UIApplication.new
21
22
 
22
- def UIA.OnCreateUICommand(*args)
23
- UICH.QueryInterface(UICH.class::IID, args[-1])
23
+ def UIA.OnCreateUICommand(*args)
24
+ UICH.QueryInterface(UICH.class::IID, args[-1])
24
25
 
25
- S_OK
26
- end
26
+ S_OK
27
+ end
27
28
 
28
- UIF = UIFramework.new
29
+ UIF = UIFramework.new
29
30
 
30
- Fzeet::Application.run { |window|
31
31
  UIF.Initialize(window.handle, UIA)
32
32
  UIF.LoadUI(LoadRibbonDll(), "APPLICATION_RIBBON\0".encode('utf-16le'))
33
33
 
@@ -60,9 +60,24 @@ module Fzeet
60
60
  handlers.each { |k, v| on(k, &v) }
61
61
 
62
62
  case _opts[:anchor]
63
- when :ltr; @parent.on(:size) { self.position = @parent.rect.tap { |r| r[:bottom] = _opts[:height] }.to_a }
64
- when :lrb; @parent.on(:size) { self.position = @parent.rect.tap { |r| r[:top] = r[:bottom] - _opts[:height]; r[:bottom] = _opts[:height] }.to_a }
65
- when :ltrb; @parent.on(:size) { self.position = @parent.rect.to_a }
63
+ when :ltr
64
+ @parent.on(:size) { |args|
65
+ self.position = @parent.rect.tap { |r| r[:bottom] = _opts[:height] }.to_a
66
+
67
+ args[:result] = nil if @parent.class == MDIChild
68
+ }
69
+ when :lrb
70
+ @parent.on(:size) { |args|
71
+ self.position = @parent.rect.tap { |r| r[:top] = r[:bottom] - _opts[:height]; r[:bottom] = _opts[:height] }.to_a
72
+
73
+ args[:result] = nil if @parent.class == MDIChild
74
+ }
75
+ when :ltrb
76
+ @parent.on(:size) { |args|
77
+ self.position = @parent.rect.to_a
78
+
79
+ args[:result] = nil if @parent.class == MDIChild
80
+ }
66
81
  else raise ArgumentError, "Bad anchor spec: #{_opts[:anchor]}."
67
82
  end if _opts[:anchor]
68
83
  end
@@ -0,0 +1,66 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ class ExplorerBrowser < Windows::ExplorerBrowser
5
+ def initialize(parent)
6
+ @parent = parent
7
+
8
+ super()
9
+
10
+ @events = Windows::ExplorerBrowserEvents.new
11
+
12
+ @events.instance_variable_set(:@browser, self)
13
+
14
+ class << @events
15
+ attr_reader :browser
16
+
17
+ def OnNavigationPending(*args)
18
+ Windows::S_OK
19
+ end
20
+
21
+ def OnViewCreated(*args)
22
+ Windows::S_OK
23
+ end
24
+
25
+ def OnNavigationComplete(*args)
26
+ Windows::S_OK
27
+ end
28
+
29
+ def OnNavigationFailed(*args)
30
+ Windows::S_OK
31
+ end
32
+ end
33
+
34
+ @cookie = nil
35
+ FFI::MemoryPointer.new(:ulong) { |p| Advise(@events, p); @cookie = p.get_ulong(0) }
36
+
37
+ Initialize(@parent.handle, parent.rect, nil)
38
+
39
+ @parent.
40
+ on(:size) { SetRect(nil, @parent.rect) }.
41
+ on(:destroy) { Unadvise(@cookie); @events.Release; Destroy(); Release() }.
42
+
43
+ instance_variable_set(:@__ExplorerBrowser__, self)
44
+ end
45
+
46
+ attr_reader :parent, :events
47
+
48
+ def goto(where)
49
+ pidl = nil
50
+
51
+ FFI::MemoryPointer.new(:pointer) { |p|
52
+ Windows.SHGetKnownFolderIDList(Windows.const_get("FOLDERID_#{where}"), 0, nil, p)
53
+
54
+ BrowseToIDList(pidl = p.read_pointer, 0)
55
+ }
56
+
57
+ self
58
+ ensure
59
+ Windows.CoTaskMemFree(pidl)
60
+ end
61
+
62
+ def back; BrowseToIDList(nil, Windows::SBSP_NAVIGATEBACK); self end
63
+ def forward; BrowseToIDList(nil, Windows::SBSP_NAVIGATEFORWARD); self end
64
+ def up; BrowseToIDList(nil, Windows::SBSP_PARENT); self end
65
+ end
66
+ end
@@ -39,6 +39,9 @@ module Fzeet
39
39
 
40
40
  def tabWidth; sendmsg(:gettabwidth) end
41
41
  def tabWidth=(tabWidth) sendmsg(:settabwidth, tabWidth) end
42
+
43
+ def dirty?; @dirty end
44
+ def dirty=(dirty) (dirty) ? @dirty = true : sendmsg(:setsavepoint) end
42
45
  end
43
46
 
44
47
  class Scintilla < Control
@@ -88,6 +91,11 @@ module Fzeet
88
91
  def initialize(parent, id, opts = {}, &block)
89
92
  super('Scintilla', parent, id, opts)
90
93
 
94
+ @dirty = false
95
+
96
+ on(:savepointleft) { @dirty = true }
97
+ on(:savepointreached) { @dirty = false }
98
+
91
99
  @parent.on(:notify, @id, &block) if block
92
100
  end
93
101
 
@@ -0,0 +1,174 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ class WebBrowser < Windows::WebBrowser
5
+ def initialize(parent)
6
+ @parent = parent
7
+
8
+ @oips = Windows::OleInPlaceSite.new
9
+
10
+ @oips.instance_variable_set(:@browser, self)
11
+
12
+ class << @oips
13
+ attr_reader :browser
14
+
15
+ def CanInPlaceActivate
16
+ Windows::S_OK
17
+ end
18
+
19
+ def GetWindow(phwnd)
20
+ phwnd.write_pointer(browser.parent.handle)
21
+
22
+ Windows::S_OK
23
+ end
24
+
25
+ def GetWindowContext(pframe, pdoc, prPos, prClip, pinfo)
26
+ pframe.write_pointer(0)
27
+ pdoc.write_pointer(0)
28
+ Windows.GetClientRect(browser.parent.handle, prPos)
29
+ Windows.GetClientRect(browser.parent.handle, prClip)
30
+
31
+ Windows::S_OK
32
+ end
33
+
34
+ def OnPosRectChange(prPos)
35
+ browser.QueryInstance(Windows::OleInPlaceObject) { |oipo|
36
+ oipo.SetObjectRects(prPos, prPos)
37
+ }
38
+
39
+ Windows::S_OK
40
+ end
41
+ end
42
+
43
+ @ocs = Windows::OleClientSite.new
44
+
45
+ @ocs.instance_variable_set(:@browser, self)
46
+
47
+ class << @ocs
48
+ attr_reader :browser
49
+
50
+ def QueryInterface(piid, ppv)
51
+ if Windows::GUID.new(piid) == Windows::IOleInPlaceSite::IID
52
+ ppv.write_pointer(browser.oips); browser.oips.AddRef
53
+
54
+ return Windows::S_OK
55
+ end
56
+
57
+ super
58
+ end
59
+ end
60
+
61
+ super()
62
+
63
+ @events = Windows::WebBrowserEvents.new
64
+
65
+ @events.instance_variable_set(:@browser, self)
66
+
67
+ class << @events
68
+ attr_reader :browser
69
+
70
+ bstrs = []
71
+
72
+ params = Class.new(FFI::Struct) {
73
+ layout \
74
+ :array, [Windows::PARAMDATA, 1]
75
+ }.new
76
+
77
+ param1 = params[:array][0]
78
+
79
+ param1[:szName] = bstrs.push(Windows::SysAllocString("URL\0".encode('utf-16le'))).last
80
+ param1[:vt] = Windows::VT_BSTR
81
+
82
+ methods = Class.new(FFI::Struct) {
83
+ layout \
84
+ :array, [Windows::METHODDATA, 1]
85
+ }.new
86
+
87
+ method1 = methods[:array][0]
88
+
89
+ method1[:szName] = bstrs.push(Windows::SysAllocString("NavigateComplete\0".encode('utf-16le'))).last
90
+ method1[:ppdata] = params[:array]
91
+ method1[:dispid] = Windows::DISPID_NAVIGATECOMPLETE
92
+ method1[:iMeth] = 8
93
+ method1[:cc] = Windows::CC_STDCALL
94
+ method1[:cArgs] = 1
95
+ method1[:wFlags] = Windows::DISPATCH_METHOD
96
+ method1[:vtReturn] = Windows::VT_EMPTY
97
+
98
+ interface = Windows::INTERFACEDATA.new
99
+
100
+ interface[:pmethdata] = methods[:array]
101
+ interface[:cMembers] = 1
102
+
103
+ FFI::MemoryPointer.new(:pointer) { |pinfo|
104
+ Windows.DetonateHresult(:CreateDispTypeInfo, interface, Windows.GetSystemDefaultLCID, pinfo)
105
+
106
+ TypeInfo = pinfo.read_pointer
107
+ }
108
+
109
+ bstrs.each { |bstr| Windows.SysFreeString(bstr) }
110
+
111
+ def Invoke(dispid, *rest)
112
+ return Windows::E_NOTIMPL unless dispid == Windows::DISPID_NAVIGATECOMPLETE
113
+
114
+ Windows.DetonateHresult(:DispInvoke, self, TypeInfo, dispid, *rest[2..-1])
115
+
116
+ Windows::S_OK
117
+ end
118
+ end
119
+
120
+ QueryInstance(Windows::ConnectionPointContainer) { |cpc|
121
+ FFI::MemoryPointer.new(:pointer) { |pcp|
122
+ cpc.FindConnectionPoint(Windows::WebBrowserEvents::IID, pcp)
123
+
124
+ @cp = Windows::ConnectionPoint.new(pcp.read_pointer)
125
+ }
126
+ }
127
+
128
+ @cookie = nil
129
+ FFI::MemoryPointer.new(:ulong) { |p| @cp.Advise(@events, p); @cookie = p.get_ulong(0) }
130
+
131
+ QueryInstance(Windows::OleObject) { |oo|
132
+ oo.SetClientSite(@ocs)
133
+ oo.DoVerb(Windows::OLEIVERB_INPLACEACTIVATE, nil, @ocs, 0, @parent.handle, @parent.rect)
134
+ }
135
+
136
+ @parent.
137
+ on(:size) {
138
+ r = @parent.rect
139
+
140
+ put_Top(r[:top]); put_Left(r[:left]); put_Width(r[:right]); put_Height(r[:bottom])
141
+ }.
142
+
143
+ on(:destroy) {
144
+ @oips.Release
145
+ @ocs.Release
146
+ @cp.Unadvise(@cookie)
147
+ @events.Release
148
+ @cp.Release
149
+ Release()
150
+ }.
151
+
152
+ instance_variable_set(:@__WebBrowser__, self)
153
+ end
154
+
155
+ attr_reader :parent, :oips, :ocs, :events, :cp
156
+
157
+ def goto(where)
158
+ where = Windows.SysAllocString("#{where}\0".encode('utf-16le'))
159
+
160
+ Navigate(where, nil, nil, nil, nil)
161
+
162
+ self
163
+ ensure
164
+ Windows.SysFreeString(where)
165
+ end
166
+
167
+ def back; GoBack(); self; rescue; self end
168
+ def forward; GoForward(); self; rescue; self end
169
+ def home; GoHome(); self end
170
+ def search; GoSearch(); self end
171
+
172
+ def refresh; Refresh(); self end
173
+ end
174
+ end
data/lib/fzeet/Control.rb CHANGED
@@ -15,3 +15,5 @@ require_relative 'Control/TreeView'
15
15
  require_relative 'Control/ProgressBar'
16
16
  require_relative 'Control/PropertySheet'
17
17
  require_relative 'Control/Tab'
18
+ require_relative 'Control/ExplorerBrowser' if Fzeet::Windows::WINVER.AtLeastWindowsVista?
19
+ require_relative 'Control/WebBrowser'
@@ -31,7 +31,7 @@ module Fzeet
31
31
  @struct[:hInstance] = Windows.GetModuleHandle(nil)
32
32
  @struct[:lpstrFile] = @buf = FFI::MemoryPointer.new(:char, 4096)
33
33
  @struct[:nMaxFile] = @buf.size
34
- @struct[:Flags] = Fzeet.flags([:enablehook, :explorer, :enablesizing] + [*_opts[:flags]], :ofn_)
34
+ @struct[:Flags] = Fzeet.flags([:enablehook, :explorer, :enablesizing, :overwriteprompt] + [*_opts[:flags]], :ofn_)
35
35
  @struct[:lCustData] = object_id
36
36
  @struct[:lpfnHook] = HookProc
37
37
 
@@ -70,6 +70,12 @@ module Fzeet
70
70
 
71
71
  result.map! { |name| "#{path}\\#{name}" }
72
72
  end
73
+
74
+ def multiselect=(multiselect)
75
+ (multiselect) ?
76
+ @struct[:Flags] |= Windows::OFN_ALLOWMULTISELECT :
77
+ @struct[:Flags] &= ~Windows::OFN_ALLOWMULTISELECT
78
+ end
73
79
  end
74
80
 
75
81
  class FileSaveDialog < FileDialog
@@ -59,6 +59,18 @@ module Fzeet
59
59
  Release()
60
60
  end if block_given?
61
61
  end
62
+
63
+ def multiselect=(multiselect)
64
+ if multiselect
65
+ SetOptions(Windows::FOS_ALLOWMULTISELECT)
66
+ else
67
+ opts = nil
68
+
69
+ FFI::MemoryPointer.new(:pointer) { |p| GetOptions(p); opts = p.get_ulong(0) }
70
+
71
+ SetOptions(opts & ~Windows::FOS_ALLOWMULTISELECT)
72
+ end
73
+ end
62
74
  end
63
75
 
64
76
  class ShellFileSaveDialog < Windows::FileSaveDialog