wxruby3 0.9.4 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/INSTALL.md +315 -78
  3. data/README.md +32 -21
  4. data/ext/wxruby3/include/wxruby-ComboPopup.h +777 -0
  5. data/lib/wx/core/combo_ctrl.rb +171 -0
  6. data/lib/wx/core/ext.rb +22 -3
  7. data/lib/wx/doc/comboctrl.rb +128 -3
  8. data/lib/wx/doc/owner_drawn_combobox.rb +5 -1
  9. data/lib/wx/version.rb +1 -1
  10. data/lib/wx/wxruby/base.rb +6 -4
  11. data/lib/wx/wxruby/cmd/sampler.rb +39 -29
  12. data/lib/wx/wxruby/cmd/setup.rb +122 -0
  13. data/lib/wx/wxruby/cmd/test.rb +56 -6
  14. data/rakefile +14 -0
  15. data/rakelib/bin.rake +48 -0
  16. data/rakelib/bin.rb +62 -0
  17. data/rakelib/build.rb +11 -7
  18. data/rakelib/config.rake +3 -1
  19. data/rakelib/configure.rb +28 -8
  20. data/rakelib/doc.rake +3 -1
  21. data/rakelib/gem.rake +169 -0
  22. data/rakelib/gem.rb +82 -0
  23. data/rakelib/install.rb +2 -0
  24. data/rakelib/lib/config/linux.rb +24 -2
  25. data/rakelib/lib/config/macosx.rb +16 -0
  26. data/rakelib/lib/config/mingw.rb +133 -9
  27. data/rakelib/lib/config/pkgman/arch.rb +53 -0
  28. data/rakelib/lib/config/pkgman/base.rb +169 -0
  29. data/rakelib/lib/config/pkgman/debian.rb +66 -0
  30. data/rakelib/lib/config/pkgman/macosx.rb +183 -0
  31. data/rakelib/lib/config/pkgman/rhel.rb +54 -0
  32. data/rakelib/lib/config/pkgman/suse.rb +54 -0
  33. data/rakelib/lib/config/unixish.rb +36 -19
  34. data/rakelib/lib/config.rb +254 -61
  35. data/rakelib/lib/core/include/funcall.inc +2 -1
  36. data/rakelib/lib/core/package.rb +47 -49
  37. data/rakelib/lib/director/comboctrl.rb +104 -3
  38. data/rakelib/lib/director/defs.rb +1 -3
  39. data/rakelib/lib/director/gdicommon.rb +5 -0
  40. data/rakelib/lib/director/menu_item.rb +1 -1
  41. data/rakelib/lib/director/num_validator.rb +5 -7
  42. data/rakelib/lib/director/owner_drawn_combobox.rb +1 -0
  43. data/rakelib/lib/director/persistent_window.rb +2 -2
  44. data/rakelib/lib/director/pgeditor.rb +1 -1
  45. data/rakelib/lib/director/pgproperties.rb +3 -3
  46. data/rakelib/lib/director/pgproperty.rb +5 -1
  47. data/rakelib/lib/director/richtext_style_listbox.rb +5 -0
  48. data/rakelib/lib/director/sizer.rb +1 -1
  49. data/rakelib/lib/director/window.rb +4 -0
  50. data/rakelib/lib/extractor/module.rb +15 -0
  51. data/rakelib/lib/generate/doc/combo_ctrl.yaml +135 -0
  52. data/rakelib/lib/generate/doc/file_dialog_customize_hook.yaml +62 -0
  53. data/rakelib/lib/generate/doc/file_system.yaml +28 -0
  54. data/rakelib/lib/generate/doc.rb +29 -14
  55. data/rakelib/lib/generate/interface.rb +16 -6
  56. data/rakelib/lib/swig_runner.rb +18 -15
  57. data/rakelib/lib/typemap/combo_popup.rb +42 -0
  58. data/rakelib/prepost.rake +9 -4
  59. data/rakelib/yard/templates/default/fulldoc/html/css/wxruby3.css +14 -0
  60. data/rakelib/yard/templates/default/fulldoc/html/setup.rb +5 -5
  61. data/rakelib/yard/yard/relative_markdown_links.rb +7 -1
  62. data/tests/test_combo_ctrl.rb +196 -0
  63. metadata +28 -17
  64. data/ext/mkrf_conf_srcgem.rb +0 -67
  65. data/rakelib/run.rake +0 -52
@@ -26,22 +26,30 @@ module WXRuby3
26
26
  WX_GLOBAL_CONSTANTS=false
27
27
  require 'wx'
28
28
  def handle_module(mod, table)
29
+ Wx.delayed_constants_for(mod).each do |key, delayed_const|
30
+ table[key.sym.to_s] = { type: true, value: delayed_const.to_s }
31
+ end
29
32
  mod.constants.each do |c|
30
33
  a_const = mod.const_get(c)
31
34
  if (::Module === a_const || ::Class === a_const) && a_const.name.start_with?('Wx::') # Wx:: Package submodule or Class (possibly Enum)
32
35
  handle_module(a_const, table[c.to_s] = {})
33
36
  elsif Wx::Enum === a_const
34
- table[c.to_s] = { type: a_const.class.name.split('::').last, value: "\#{a_const.class}.new(\#{a_const.to_i})" }
35
- elsif !(::Hash === a_const || ::Array === a_const)
36
- table[c.to_s] = { type: a_const.class.name.split('::').last, value: a_const } unless c == :THE_APP
37
+ table[c.to_s] = { type: true, value: "\#{a_const.class}.new(\#{a_const.to_i})" }
38
+ elsif !(::Hash === a_const || ::Array === a_const)
39
+ case a_const
40
+ when Wx::Size
41
+ table[c.to_s] = { type: true, value: "Wx::Size.new(\#{a_const.width}, \#{a_const.height})" }
42
+ when Wx::Point
43
+ table[c.to_s] = { type: true, value: "Wx::Point.new(\#{a_const.x}, \#{a_const.y})" }
44
+ else
45
+ table[c.to_s] = { type: true, value: a_const } unless c == :THE_APP
46
+ end
37
47
  end
38
48
  end
39
49
  end
40
- Wx::App.run do
41
- table = { 'Wx' => {}}
42
- handle_module(Wx, table['Wx'])
43
- STDOUT.puts JSON.dump(table)
44
- end
50
+ table = { 'Wx' => {}}
51
+ handle_module(Wx, table['Wx'])
52
+ STDOUT.puts JSON.dump(table)
45
53
  __SCRIPT
46
54
  STDERR.puts "* executing constants collection script:\n#{script}" if Director.trace?
47
55
  begin
@@ -693,15 +701,22 @@ module WXRuby3
693
701
  # at least 2 newlines to make Yard skip/forget the header comment
694
702
  fdoc.puts
695
703
  fdoc.puts
696
- fdoc.puts "module #{package.fullname}"
697
- fdoc.puts
698
- fdoc.indent do
704
+ mod_indent = 0
705
+ package.all_modules.each do |modnm|
706
+ fdoc.iputs("module #{package.fullname}", mod_indent)
707
+ fdoc.puts
708
+ mod_indent += 1
709
+ end
710
+ fdoc.indent(mod_indent) do
699
711
  gen_constants_doc(fdoc)
700
712
  gen_functions_doc(fdoc) unless no_gen?(:functions)
701
713
  gen_class_doc(fdoc) unless no_gen?(:classes)
702
714
  end
703
- fdoc.puts
704
- fdoc.puts 'end'
715
+ package.all_modules.each do |_|
716
+ fdoc.puts
717
+ fdoc.iputs('end', mod_indent)
718
+ mod_indent -= 1
719
+ end
705
720
  end
706
721
  end
707
722
 
@@ -742,7 +757,7 @@ module WXRuby3
742
757
  end
743
758
 
744
759
  def gen_constant_value(val)
745
- if ::String === val && /\A(#<(.*)>|[\w:]+\.new\(.*\))\Z/ =~ val
760
+ if ::String === val && /\A(#<(.*)>|[\w:]+\.\w+\(.*\))\Z/ =~ val
746
761
  if $2
747
762
  valstr = $2
748
763
  if /\Awx/ =~ valstr
@@ -547,10 +547,18 @@ module WXRuby3
547
547
  if Extractor::EnumDef === item && !item.ignored && !item.items.all? {|e| e.ignored }
548
548
  fout.puts
549
549
  fout.puts "// from enum #{item.is_anonymous ? '' : item.name}"
550
- fout.puts "enum #{item.name};" unless item.is_anonymous
551
- item.items.each do |e|
552
- unless e.ignored
553
- fout.puts "%constant int #{e.name} = #{e.fqn};"
550
+ if item.is_anonymous
551
+ item.items.each do |e|
552
+ unless e.ignored
553
+ fout.puts "%constant int #{e.name} = #{e.fqn};"
554
+ end
555
+ end
556
+ else
557
+ fout.puts "enum #{item.name};"
558
+ item.items.each do |e|
559
+ unless e.ignored
560
+ fout.puts "%constant int #{item.name}_#{e.name} = #{e.fqn};"
561
+ end
554
562
  end
555
563
  end
556
564
  end
@@ -595,7 +603,8 @@ module WXRuby3
595
603
  elsif item.value =~ /wx(Colour|Font)(\(.*\))/
596
604
  frbext = init_rb_ext_file unless frbext
597
605
  frbext.indent do
598
- frbext.puts "Wx.add_delayed_constant(self, :#{rb_constant_name(item.name)}) { Wx::#{$1}.new#{$2} }"
606
+ code = "Wx::#{$1}.new#{$2}"
607
+ frbext.puts "Wx.add_delayed_constant(self, :#{rb_constant_name(item.name)}, '#{code}') { #{code} }"
599
608
  end
600
609
  frbext.puts
601
610
  elsif item.value =~ /wxSystemSettings::(\w+)\((.*)\)/
@@ -603,7 +612,8 @@ module WXRuby3
603
612
  setting_mtd = $1
604
613
  args = $2.split(',').collect {|a| rb_constant_value(a) }.join(', ')
605
614
  frbext.indent do
606
- frbext.puts "Wx.add_delayed_constant(self, :#{rb_constant_name(item.name)}) { Wx::SystemSettings.#{rb_method_name(setting_mtd)}(#{args}) }"
615
+ code = "Wx::SystemSettings.#{rb_method_name(setting_mtd)}(#{args})"
616
+ frbext.puts "Wx.add_delayed_constant(self, :#{rb_constant_name(item.name)}, '#{code}') { #{code} }"
607
617
  end
608
618
  frbext.puts
609
619
  else
@@ -43,24 +43,23 @@ module WXRuby3
43
43
  @swig_version
44
44
  end
45
45
 
46
-
47
46
  def check_swig
48
47
  begin
49
48
  @swig_version = `#{WXRuby3::Config.get_config('swig')} -version`[/\d+\.\d+\.\d+/]
50
49
  rescue Exception
51
- STDERR.puts "ERROR: Could not run SWIG (#{WXRuby3::Config.get_config('swig')})"
50
+ $stderr.puts "ERROR: Could not run SWIG (#{WXRuby3::Config.get_config('swig')})"
52
51
  exit(1)
53
52
  end
54
53
 
55
- # Very old versions put --version on STDERR, not STDOUT
54
+ # Very old versions put --version on $stderr, not $stdout
56
55
  unless @swig_version
57
- STDERR.puts "Could not get version info from SWIG; " +
56
+ $stderr.puts "Could not get version info from SWIG; " +
58
57
  "is a very old version installed?.\n"
59
58
  exit(1)
60
59
  end
61
60
 
62
61
  if @swig_version < SWIG_MINIMUM_VERSION
63
- STDERR.puts "SWIG version #{@swig_version} is installed, " +
62
+ $stderr.puts "SWIG version #{@swig_version} is installed, " +
64
63
  "minimum version required is #{SWIG_MINIMUM_VERSION}.\n"
65
64
  exit(1)
66
65
  end
@@ -72,11 +71,12 @@ module WXRuby3
72
71
  check_swig unless swig_state
73
72
  inc_paths = "-I#{config.wxruby_dir} -I#{config.swig_dir}/custom"
74
73
  inc_paths << " -I#{config.swig_dir}/custom/swig#{swig_major}"
75
- sh "#{config.get_config('swig')} #{config.wx_cppflags.join(' ')} " +
76
- "#{config.extra_cppflags.join(' ')} #{config.verbose_flag} #{inc_paths} " +
77
- #"-w401 -w801 -w515 -c++ -ruby " +
78
- "-w801 -c++ -ruby " +
79
- "-o #{target} #{source}"
74
+ WXRuby3.config.sh "#{config.get_config('swig')} #{config.wx_cppflags.join(' ')} " +
75
+ "#{config.extra_cppflags.join(' ')} #{config.verbose_flag} #{inc_paths} " +
76
+ #"-w401 -w801 -w515 -c++ -ruby " +
77
+ "-w801 -c++ -ruby " +
78
+ "-o #{target} #{source}",
79
+ fail_on_error: true
80
80
  end
81
81
 
82
82
  end
@@ -205,7 +205,7 @@ module WXRuby3
205
205
  end
206
206
 
207
207
  def self.run(pid, director, target)
208
- puts "Processor.#{pid}: #{target}"
208
+ Config.instance.log_progress("Processor.#{pid}: #{target}")
209
209
  const_get(camelize(pid.to_s)).new(director, target).run
210
210
  end
211
211
 
@@ -262,7 +262,7 @@ module WXRuby3
262
262
  def_items.each do |item|
263
263
  case item
264
264
  when Extractor::EnumDef
265
- item.items.each { |e| enumerators[rb_wx_name(e.name)] = item } if item.is_type
265
+ item.items.each { |e| enumerators["#{rb_wx_name(item.name)}_#{e.name}"] = item } if item.is_type
266
266
  when Extractor::ClassDef
267
267
  item.items.select { |itm| Extractor::EnumDef === itm }.each do |enum|
268
268
  enum.items.each { |e| enumerators[rb_wx_name(e.name)] = enum } if enum.is_type
@@ -334,6 +334,7 @@ module WXRuby3
334
334
  fix_enum = true
335
335
  enum_item = enum_table[md[2]]
336
336
  enum_name = rb_wx_name(enum_item.name)
337
+ enumerator_name = rb_wx_name(md[2].sub(/\A#{enum_name}_/, ''))
337
338
  enum_id = enum_item.scope.empty? ? enum_name : "#{rb_wx_name(enum_item.scope)}::#{enum_name}"
338
339
  enum_var = enum_id.gsub('::', '_')
339
340
  line = [
@@ -343,7 +344,7 @@ module WXRuby3
343
344
  # add enum class constant to current module (use unscoped name)
344
345
  " rb_define_const(#{md[1]}, \"#{enum_name}\", cWx#{enum_var}); // Inserted by fixmodule.rb",
345
346
  # create enumerator value const under new enum class
346
- " wxRuby_AddEnumValue(cWx#{enum_var}, \"#{md[2]}\"#{md[3]} // Updated by fixmodule.rb"
347
+ " wxRuby_AddEnumValue(cWx#{enum_var}, \"#{enumerator_name}\"#{md[3]} // Updated by fixmodule.rb"
347
348
  ].join("\n")
348
349
  end
349
350
  else
@@ -352,13 +353,15 @@ module WXRuby3
352
353
  # of the same enum?
353
354
  if enum_item && enum_table[md[2]] == enum_item
354
355
  enum_name = rb_wx_name(enum_item.name)
356
+ enumerator_name = rb_wx_name(md[2].sub(/\A#{enum_name}_/, ''))
355
357
  enum_id = enum_item.scope.empty? ? enum_name : "#{rb_wx_name(enum_item.scope)}::#{enum_name}"
356
358
  enum_var = enum_id.gsub('::', '_')
357
359
  # create enumerator value const under new enum class
358
- line = " wxRuby_AddEnumValue(cWx#{enum_var}, \"#{md[2]}\"#{md[3]} // Updated by fixmodule.rb"
360
+ line = " wxRuby_AddEnumValue(cWx#{enum_var}, \"#{enumerator_name}\"#{md[3]} // Updated by fixmodule.rb"
359
361
  else # we found the start of another enum
360
362
  enum_item = enum_table[md[2]]
361
363
  enum_name = rb_wx_name(enum_item.name)
364
+ enumerator_name = rb_wx_name(md[2].sub(/\A#{enum_name}_/, ''))
362
365
  enum_id = enum_item.scope.empty? ? enum_name : "#{rb_wx_name(enum_item.scope)}::#{enum_name}"
363
366
  enum_var = enum_id.gsub('::', '_')
364
367
  line = [
@@ -368,7 +371,7 @@ module WXRuby3
368
371
  # add enum class constant to current module (use unscoped name)
369
372
  " rb_define_const(#{md[1]}, \"#{enum_name}\", cWx#{enum_var}); // Inserted by fixmodule.rb",
370
373
  # create enumerator value const under new enum class
371
- " wxRuby_AddEnumValue(cWx#{enum_var}, \"#{md[2]}\"#{md[3]} // Updated by fixmodule.rb"
374
+ " wxRuby_AddEnumValue(cWx#{enum_var}, \"#{enumerator_name}\"#{md[3]} // Updated by fixmodule.rb"
372
375
  ].join("\n")
373
376
  end
374
377
  else # end of enum def
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2023 M.J.N. Corino, The Netherlands
2
+ #
3
+ # This software is released under the MIT license.
4
+
5
+ ###
6
+ # wxRuby3 wxComboPopup typemap definition
7
+ ###
8
+
9
+ require_relative '../core/mapping'
10
+
11
+ module WXRuby3
12
+
13
+ module Typemap
14
+
15
+ module ComboPopup
16
+
17
+ include Typemap::Module
18
+
19
+ define do
20
+
21
+ # for DoSetPopupControl
22
+ map 'wxComboPopup* popup' => 'Wx::ComboPopup,nil' do
23
+
24
+ add_header_code <<~__CODE
25
+ #include <wx/combo.h>
26
+
27
+ WXRUBY_EXPORT wxComboPopup* wxRuby_ComboPopupFromRuby(VALUE popup);
28
+ WXRUBY_EXPORT VALUE wxRuby_ComboPopupToRuby(wxComboPopup* popup);
29
+ __CODE
30
+
31
+ map_in code: '$1 = wxRuby_ComboPopupFromRuby($input);'
32
+
33
+ map_directorin code: '$input = wxRuby_ComboPopupToRuby($1);'
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
data/rakelib/prepost.rake CHANGED
@@ -23,16 +23,21 @@ namespace 'wxruby' do
23
23
 
24
24
  namespace 'post' do
25
25
 
26
- task :srcgem => %w[gem:wxwin gem:install wxruby:doc] do
26
+ task :srcgem => %w[gem:wxwin gem:install] do
27
+ $stdout.print "Generating wxRuby3 reference documentation..." if WXRuby3.config.run_silent?
28
+ Rake::Task['wxruby:doc'].invoke
29
+ $stdout.puts 'done!' if WXRuby3.config.run_silent?
27
30
  # cleanup
28
- rm_rf('rakelib')
29
- rm_rf('ext/wxruby3')
30
- rm_rf('ext/wxWidgets') if File.exist?('ext/wxWidgets')
31
+ rm_rf('rakelib', verbose: !WXRuby3.config.run_silent?)
32
+ rm_rf('ext/wxruby3', verbose: !WXRuby3.config.run_silent?)
33
+ WXRuby3.config.cleanup_bootstrap
34
+ File.open(File.join(WXRuby3::Config.wxruby_root, 'ext', 'wxruby.setup.done'), 'w') { |f| f << '1' }
31
35
  end
32
36
 
33
37
  task :bingem => 'gem:install' do
34
38
  # cleanup
35
39
  rm_rf('rakelib')
40
+ File.open(File.join(WXRuby3::Config.wxruby_root, 'ext', 'wxruby.setup.done'), 'w') { |f| f << '1' }
36
41
  end
37
42
 
38
43
  namespace 'gem' do
@@ -77,3 +77,17 @@ div.wxrb-logo table td {
77
77
  font-weight: bold;
78
78
  font-size: 0.9em;
79
79
  }
80
+
81
+ #filecontents {
82
+ margin-right: 340px;
83
+ }
84
+
85
+ #filecontents blockquote {
86
+ border-left: .5em solid #e0e0e0;
87
+ margin: 10px;
88
+ padding-left: 10px;
89
+ }
90
+
91
+ #toc {
92
+ position: fixed;
93
+ }
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  def init
4
- # It seems YARD messes things up so that a number of classes are not properly
4
+ # It seems YARD messes things up so that a lot of classes, modules and constants are not properly
5
5
  # registered in their enclosing namespaces.
6
6
  # This hack makes sure that if that is the case we fix that here.
7
- all_classes = Registry.all(:class)
8
- all_classes.each do |c|
7
+ all_objects = Registry.all(:class, :constant, :module)
8
+ all_objects.each do |c|
9
9
  if (ns = c.namespace)
10
10
  unless ns.children.any? { |nsc| nsc.path == c.path }
11
- ns.children << c # class missing from child list of enclosing namespace -> add here
11
+ ns.children << c # class/module/constant missing from child list of enclosing namespace -> add here
12
12
  end
13
13
  end
14
14
  if (ns = Registry[c.namespace.path])
15
15
  unless ns.children.any? { |nsc| nsc.path == c.path }
16
- ns.children << c # class missing from child list of enclosing namespace -> add here
16
+ ns.children << c # class/module/constant missing from child list of enclosing namespace -> add here
17
17
  end
18
18
  end
19
19
  end
@@ -31,12 +31,18 @@ module YARD # rubocop:disable Style/Documentation
31
31
  if fnames.include?(href.path)
32
32
  link.replace "{file:#{href} #{link.inner_html}}"
33
33
  elsif href.path.end_with?('_md.html') && (fname = fnames.find {|fnm| fnm.end_with?(href.path.sub(/_md.html\Z/, '.md')) })
34
- link.replace "{file:#{fname} #{link.inner_html}}"
34
+ link.replace "{file:#{fname}#{href.fragment ? "##{fragment_to_yard(href.fragment)}" : ''} #{link.inner_html}}"
35
35
  end
36
36
  end
37
37
  end
38
38
  super(html.to_s)
39
39
  end
40
+
41
+ # this does not work with mixed case labels but is good enough for us
42
+ def fragment_to_yard(s)
43
+ s.start_with?('label-') ? s : "label-#{s.gsub('-', '+').capitalize}"
44
+ end
45
+
40
46
  end
41
47
 
42
48
  Templates::Template.extra_includes << RelativeMarkdownLinks
@@ -0,0 +1,196 @@
1
+ # Copyright (c) 2023 M.J.N. Corino, The Netherlands
2
+ #
3
+ # This software is released under the MIT license.
4
+
5
+ require_relative './lib/wxframe_runner'
6
+ require_relative './lib/text_entry_tests'
7
+
8
+ class ComboCtrlCtrlTests < WxRuby::Test::GUITests
9
+
10
+ include TextEntryTests
11
+
12
+ class LVComboPopup < Wx::ListView
13
+
14
+ include Wx::ComboPopup
15
+
16
+ def initialize
17
+ # call default control ctor; need to call Wx::ListView#create later
18
+ super
19
+ end
20
+
21
+ def init
22
+ @value = -1
23
+ end
24
+
25
+ def create(parent)
26
+ # need to finish creating the list view here
27
+ # as calling super here would just call Wx::ComboPopup#create and not Wx::ListView#create
28
+ # we need to use Ruby magic
29
+ wx_lv_create = (Wx::ListView.instance_method :create).bind(self)
30
+ wx_lv_create.call(parent, 1, [0,0], Wx::DEFAULT_SIZE)
31
+ evt_motion :on_mouse_move
32
+ evt_left_up :on_mouse_click
33
+ end
34
+
35
+ # Return pointer to the created control
36
+ def get_control
37
+ self
38
+ end
39
+
40
+ def lv_find_item(*args)
41
+ unless @wx_lv_find_item
42
+ @wx_lv_find_item = (Wx::ListView.instance_method :find_item).bind(self)
43
+ end
44
+ @wx_lv_find_item.call(*args)
45
+ end
46
+ protected :lv_find_item
47
+
48
+ # Translate string into a list selection
49
+ def set_string_value(s)
50
+ n = lv_find_item(-1, s)
51
+ if n >= 0 && n < get_item_count
52
+ select(n)
53
+ @value = n
54
+ end
55
+ end
56
+
57
+ # Get list selection as a string
58
+ def get_string_value
59
+ return get_item_text(@value) if @value >= 0
60
+ ''
61
+ end
62
+
63
+ # Do mouse hot-tracking (which is typical in list popups)
64
+ def on_mouse_move(event)
65
+ # Move selection to cursor ...
66
+ end
67
+
68
+ # On mouse left up, set the value and close the popup
69
+ def on_mouse_click(_event)
70
+ @value = get_first_selected
71
+
72
+ # Send event as well ...
73
+
74
+ dismiss
75
+ end
76
+
77
+ end
78
+
79
+ def setup
80
+ super
81
+ @combo = Wx::ComboCtrl.new(frame_win, name: 'ComboCtrl')
82
+ @combo.set_popup_control(LVComboPopup.new)
83
+ end
84
+
85
+ def cleanup
86
+ @combo.destroy
87
+ super
88
+ end
89
+
90
+ attr_reader :combo
91
+ alias :text_entry :combo
92
+
93
+ def fill_list(list)
94
+ list.insert_item(0, 'This is the first item')
95
+ list.insert_item(1, 'This is the second item')
96
+ list.insert_item(2, 'This is the third item')
97
+ list.insert_item(3, 'This is the fourth item')
98
+ end
99
+
100
+ def test_popup
101
+ assert_equal('', combo.get_value)
102
+
103
+ assert_kind_of(Wx::ComboPopup, combo.get_popup_control)
104
+ assert_kind_of(Wx::ListView, combo.get_popup_control)
105
+ assert_kind_of(Wx::ListView, combo.get_popup_control.get_control)
106
+
107
+ assert_nothing_raised { fill_list(combo.get_popup_control) }
108
+ combo.popup
109
+
110
+ combo.set_value_by_user('This is the second item')
111
+
112
+ assert_equal('This is the second item', combo.get_popup_control.get_string_value)
113
+
114
+ combo.dismiss
115
+ end
116
+
117
+ end
118
+
119
+ class OwnerDrawnCBTests < WxRuby::Test::GUITests
120
+
121
+ include TextEntryTests
122
+
123
+ class TestODComboBox < Wx::OwnerDrawnComboBox
124
+
125
+ def on_draw_item(dc, rect, item, _flags)
126
+ return if item == Wx::NOT_FOUND
127
+
128
+ dc.set_text_foreground(Wx::BLACK)
129
+ dc.draw_text(get_string(item),
130
+ rect.x + 3,
131
+ rect.y + ((rect.height - dc.char_height)/2))
132
+ end
133
+
134
+ def on_draw_background(dc, rect, item, flags)
135
+ # If item is selected or even, or we are painting the
136
+ # combo control itself, use the default rendering.
137
+ if flags.anybits?(Wx::ODCB_PAINTING_CONTROL|Wx::ODCB_PAINTING_SELECTED) || (item & 1) == 0
138
+ super(dc,rect,item,flags)
139
+ return
140
+ end
141
+
142
+ # Otherwise, draw every other background with different colour.
143
+ bgCol = Wx::Colour.new(240,240,250)
144
+ dc.set_brush(Wx::Brush.new(bgCol))
145
+ dc.set_pen(Wx::Pen.new(bgCol))
146
+ dc.draw_rectangle(rect)
147
+ end
148
+
149
+ def on_measure_item(_item)
150
+ 48
151
+ end
152
+
153
+ def on_measure_item_width(_item)
154
+ -1 # default - will be measured from text width
155
+ end
156
+
157
+ end
158
+
159
+ def setup
160
+ super
161
+ @combo = TestODComboBox.new(frame_win, name: 'ODComboBox')
162
+ end
163
+
164
+ def cleanup
165
+ @combo.destroy
166
+ super
167
+ end
168
+
169
+ attr_reader :combo
170
+ alias :text_entry :combo
171
+
172
+ def fill_list(list)
173
+ list.append('This is the first item')
174
+ list.append('This is the second item')
175
+ list.append('This is the third item')
176
+ list.append('This is the fourth item')
177
+ end
178
+
179
+ def test_popup
180
+ assert_equal('', combo.get_value)
181
+
182
+ assert_kind_of(Wx::ComboPopup, combo.get_popup_control)
183
+ assert_kind_of(Wx::ComboPopupWx, combo.get_popup_control)
184
+ assert_kind_of(Wx::VListBox, combo.get_popup_control.get_control)
185
+
186
+ assert_nothing_raised { fill_list(combo) }
187
+ combo.popup
188
+
189
+ combo.set_value_by_user('This is the third item')
190
+
191
+ assert_equal('This is the third item', combo.get_popup_control.get_string_value)
192
+
193
+ combo.dismiss
194
+ end
195
+
196
+ end