wxruby3-shapes 0.9.0.pre.beta.3 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/INSTALL.md +5 -7
  3. data/README.md +38 -6
  4. data/assets/logo.svg +339 -0
  5. data/assets/logo.xpm +60 -0
  6. data/assets/screenshot.png +0 -0
  7. data/assets/social.png +0 -0
  8. data/bin/wx-shapes +1 -1
  9. data/lib/wx/shapes/arrow_base.rb +4 -11
  10. data/lib/wx/shapes/arrows/circle_arrow.rb +22 -11
  11. data/lib/wx/shapes/arrows/circle_prong_arrow.rb +48 -0
  12. data/lib/wx/shapes/arrows/cross_bar_arrow.rb +57 -0
  13. data/lib/wx/shapes/arrows/cross_bar_circle_arrow.rb +56 -0
  14. data/lib/wx/shapes/arrows/cross_bar_prong_arrow.rb +49 -0
  15. data/lib/wx/shapes/arrows/crossed_circle.rb +46 -0
  16. data/lib/wx/shapes/arrows/cup_arrow.rb +65 -0
  17. data/lib/wx/shapes/arrows/diamond_arrow.rb +8 -13
  18. data/lib/wx/shapes/arrows/double_cross_bar_arrow.rb +27 -0
  19. data/lib/wx/shapes/arrows/filled_arrow.rb +60 -0
  20. data/lib/wx/shapes/arrows/line_arrow.rb +67 -0
  21. data/lib/wx/shapes/arrows/open_arrow.rb +22 -23
  22. data/lib/wx/shapes/arrows/prong_arrow.rb +42 -0
  23. data/lib/wx/shapes/arrows/solid_arrow.rb +21 -35
  24. data/lib/wx/shapes/arrows/square_arrow.rb +37 -0
  25. data/lib/wx/shapes/auto_layout.rb +2 -2
  26. data/lib/wx/shapes/base.rb +1 -1
  27. data/lib/wx/shapes/canvas_history.rb +20 -0
  28. data/lib/wx/shapes/connection_point.rb +10 -6
  29. data/lib/wx/shapes/diagram.rb +98 -78
  30. data/lib/wx/shapes/events.rb +8 -8
  31. data/lib/wx/shapes/printout.rb +3 -16
  32. data/lib/wx/shapes/serializable.rb +2 -436
  33. data/lib/wx/shapes/serialize/wx.rb +30 -18
  34. data/lib/wx/shapes/shape.rb +211 -168
  35. data/lib/wx/shapes/shape_canvas.rb +728 -267
  36. data/lib/wx/shapes/shape_data_object.rb +99 -18
  37. data/lib/wx/shapes/shape_handle.rb +18 -11
  38. data/lib/wx/shapes/shape_list.rb +34 -67
  39. data/lib/wx/shapes/shapes/bitmap_shape.rb +23 -24
  40. data/lib/wx/shapes/shapes/box_shape.rb +389 -0
  41. data/lib/wx/shapes/shapes/circle_shape.rb +19 -22
  42. data/lib/wx/shapes/shapes/control_shape.rb +77 -41
  43. data/lib/wx/shapes/shapes/curve_shape.rb +38 -31
  44. data/lib/wx/shapes/shapes/diamond_shape.rb +7 -17
  45. data/lib/wx/shapes/shapes/edit_text_shape.rb +6 -9
  46. data/lib/wx/shapes/shapes/ellipse_shape.rb +12 -15
  47. data/lib/wx/shapes/shapes/flex_grid_shape.rb +58 -33
  48. data/lib/wx/shapes/shapes/grid_shape.rb +259 -161
  49. data/lib/wx/shapes/shapes/line_shape.rb +155 -161
  50. data/lib/wx/shapes/shapes/manager_shape.rb +77 -0
  51. data/lib/wx/shapes/shapes/multi_sel_rect.rb +8 -8
  52. data/lib/wx/shapes/shapes/ortho_shape.rb +31 -36
  53. data/lib/wx/shapes/shapes/polygon_shape.rb +23 -29
  54. data/lib/wx/shapes/shapes/rect_shape.rb +95 -53
  55. data/lib/wx/shapes/shapes/round_ortho_shape.rb +6 -8
  56. data/lib/wx/shapes/shapes/round_rect_shape.rb +20 -24
  57. data/lib/wx/shapes/shapes/square_shape.rb +14 -17
  58. data/lib/wx/shapes/shapes/text_shape.rb +95 -53
  59. data/lib/wx/shapes/version.rb +1 -1
  60. data/lib/wx/shapes/wx.rb +16 -7
  61. data/lib/wx/wx-shapes/cmd/test.rb +1 -1
  62. data/samples/demo/arrows.json +1 -0
  63. data/samples/demo/arrows.yaml +793 -0
  64. data/samples/demo/art/HBox.xpm +22 -0
  65. data/samples/demo/art/VBox.xpm +22 -0
  66. data/samples/demo/art/logo.xpm +60 -0
  67. data/samples/demo/class.json +1 -0
  68. data/samples/demo/class.yaml +5631 -0
  69. data/samples/demo/demo.rb +301 -91
  70. data/samples/demo/dialogs.rb +1405 -0
  71. data/samples/demo/erd.json +1 -0
  72. data/samples/demo/erd.yaml +4072 -0
  73. data/samples/demo/frame_canvas.rb +409 -33
  74. data/samples/sample1/art/logo.xpm +60 -0
  75. data/samples/sample1/sample.rb +11 -11
  76. data/samples/sample2/art/logo.xpm +60 -0
  77. data/samples/sample2/sample.rb +2 -2
  78. data/samples/sample2/sample_shape.rb +15 -15
  79. data/samples/sample3/art/logo.xpm +60 -0
  80. data/samples/sample3/sample.rb +3 -3
  81. data/samples/sample4/art/logo.xpm +60 -0
  82. data/samples/sample4/sample.rb +2 -2
  83. data/tests/lib/wxapp_runner.rb +4 -0
  84. data/tests/serializer_tests.rb +8 -441
  85. data/tests/test_grid_shapes.rb +2 -2
  86. data/tests/test_serialize_xml.rb +17 -0
  87. data/tests/test_serialize_yaml.rb +2 -2
  88. metadata +78 -28
  89. data/lib/wx/shapes/serialize/core.rb +0 -40
  90. data/lib/wx/shapes/serialize/id.rb +0 -82
  91. data/lib/wx/shapes/serializer/json.rb +0 -258
  92. data/lib/wx/shapes/serializer/yaml.rb +0 -125
  93. data/samples/demo/art/sample.xpm +0 -251
  94. data/samples/sample1/art/sample.xpm +0 -251
  95. data/samples/sample2/art/sample.xpm +0 -251
  96. data/samples/sample3/art/sample.xpm +0 -251
  97. data/samples/sample4/art/sample.xpm +0 -251
data/samples/demo/demo.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # Wx::SF - Demo ThumbFrame, MainFrame and App
2
2
  # Copyright (c) M.J.N. Corino, The Netherlands
3
3
 
4
+ require 'nokogiri'
4
5
  require 'wx/shapes'
6
+ require 'wx/mdap'
5
7
  require_relative './frame_canvas'
6
8
 
7
9
  class ThumbFrame < Wx::Frame
@@ -9,6 +11,8 @@ class ThumbFrame < Wx::Frame
9
11
  def initialize(parent, title: 'Thumbnail', size: Wx::Size.new( 200,150 ), style: Wx::CAPTION|Wx::FRAME_FLOAT_ON_PARENT|Wx::FRAME_TOOL_WINDOW|Wx::RESIZE_BORDER|Wx::TAB_TRAVERSAL)
10
12
  super
11
13
 
14
+ set_icon(Wx::Icon(:logo))
15
+
12
16
  set_size_hints(Wx::DEFAULT_SIZE)
13
17
 
14
18
  main_sizer = Wx::VBoxSizer.new
@@ -44,6 +48,8 @@ class MainFrame < Wx::Frame
44
48
  GRID = self.new(14)
45
49
  FLEXGRID = self.new(15)
46
50
  STANDALONELINE = self.new(16)
51
+ VBOX = self.new(17)
52
+ HBOX = self.new(18)
47
53
  end
48
54
 
49
55
  module ID
@@ -52,12 +58,20 @@ class MainFrame < Wx::Frame
52
58
  # menu IDs
53
59
  #---------------------------------------------------------------#
54
60
  M_SAVEASBITMAP = self.next_id
61
+ M_SHAPE_LIST = self.next_id
62
+ M_GRID_COLUMNS = self.next_id
63
+ M_GRIDCOLS_1 = self.next_id
64
+ M_GRIDCOLS_2 = self.next_id
65
+ M_GRIDCOLS_3 = self.next_id
66
+ M_GRIDCOLS_4 = self.next_id
67
+ M_GRIDCOLS_5 = self.next_id
68
+ M_GRIDCOLS_CUSTOM = self.next_id
69
+ M_GRIDCOLS_NR = self.next_id
55
70
 
56
71
  # tool IDs
57
72
  #---------------------------------------------------------------#
58
73
  T_FIRST_TOOLMARKER = self.next_id
59
- T_GRID = self.next_id
60
- T_SHADOW = self.next_id
74
+ T_SETTINGS = self.next_id
61
75
  T_GC = self.next_id
62
76
  T_TOOL = self.next_id
63
77
  T_RECTSHP = self.next_id
@@ -71,6 +85,8 @@ class MainFrame < Wx::Frame
71
85
  T_BITMAPSHP = self.next_id
72
86
  T_GRIDSHP = self.next_id
73
87
  T_FLEXGRIDSHP = self.next_id
88
+ T_VBOXSHP = self.next_id
89
+ T_HBOXSHP = self.next_id
74
90
  T_LINESHP = self.next_id
75
91
  T_STANDALONELINESHP = self.next_id
76
92
  T_CURVESHP = self.next_id
@@ -92,44 +108,165 @@ class MainFrame < Wx::Frame
92
108
  #---------------------------------------------------------------#
93
109
  T_COLORPICKER = self.next_id(M_AUTOLAYOUT_LAST) + 1
94
110
  end
95
-
111
+
112
+ FILE_MASK = 'JSON files (*.json)|*.json|YAML files (*.yaml,*.yml)|*.yaml;*.yml|XML files (*.xml)|*.xml'
113
+ if Wx::PLATFORM == 'WXMSW'
114
+ FILE_MASK << '|All files (*.*)|*.*'
115
+ else
116
+ FILE_MASK << '|All files (*)|*'
117
+ end
118
+
119
+ class DiagramFileDialog < Wx::FileDialogCustomizeHook
120
+
121
+ FORMATS = %w[json yaml xml]
122
+
123
+ def initialize(dlg, compact: nil)
124
+ super()
125
+ @format = nil
126
+ @compact = compact.nil? ? nil : !!compact
127
+ @choice = nil
128
+ @checkbox = nil
129
+ @dialog = dlg
130
+ @dialog.set_customize_hook(self)
131
+ end
132
+
133
+ attr_reader :format, :compact
134
+
135
+ def add_custom_controls(customizer)
136
+ customizer.add_static_text('Format:')
137
+ @choice = customizer.add_choice(FORMATS)
138
+ unless @compact.nil?
139
+ @checkbox = customizer.add_check_box('Compact content')
140
+ @checkbox.set_value(true)
141
+ end
142
+ end
143
+
144
+ def get_filter_index
145
+ if Wx::PLATFORM == 'WXGTK'
146
+ @dialog.get_filter_index
147
+ else
148
+ @dialog.get_currently_selected_filter_index
149
+ end
150
+ end
151
+
152
+ def update_custom_controls
153
+ if get_filter_index<0 || get_filter_index >= FORMATS.size
154
+ @choice.enable(true)
155
+ else
156
+ @choice.enable(false)
157
+ end
158
+ end
159
+
160
+ def transfer_data_from_custom_controls
161
+ @format = case @choice.get_selection
162
+ when Wx::NOT_FOUND then nil
163
+ else
164
+ FORMATS[@choice.get_selection].to_sym
165
+ end
166
+ @compact = @checkbox.get_value if @checkbox
167
+ @dialog = nil
168
+ end
169
+ end
170
+
96
171
  def initialize(parent, title: 'wxShapeFramework Demo Application', style: Wx::CLOSE_BOX|Wx::DEFAULT_FRAME_STYLE|Wx::RESIZE_BORDER|Wx::TAB_TRAVERSAL)
97
172
  super
98
173
 
99
- set_icon(Wx::Icon(:sample))
174
+ set_icon(Wx::Icon(:logo))
100
175
 
101
176
  setup_frame
102
177
 
103
- @file_menu.append(Wx::ID_NEW, "&New\tCtrl+N", "New chart", Wx::ITEM_NORMAL)
104
- @file_menu.append(Wx::ID_OPEN, "&Open\tCtrl+O", "Load a chart from file", Wx::ITEM_NORMAL)
105
- @file_menu.append(Wx::ID_SAVE, "&Save as...\tCtrl+Shift+S", "Save the chart to file", Wx::ITEM_NORMAL)
178
+ mi = Wx::MenuItem.new(@file_menu, Wx::ID_NEW, "&New\tCtrl+N", "New chart")
179
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_NEW, Wx::ART_MENU))
180
+ @file_menu.append mi
181
+ mi = Wx::MenuItem.new(@file_menu, Wx::ID_OPEN, "&Open\tCtrl+O", "Load a chart from file")
182
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FILE_OPEN, Wx::ART_MENU))
183
+ @file_menu.append mi
184
+ mi = Wx::MenuItem.new(@file_menu, Wx::ID_SAVE, "&Save as...\tCtrl+Shift+S", "Save the chart to file")
185
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FILE_SAVE, Wx::ART_MENU))
186
+ @file_menu.append mi
106
187
  @file_menu.append_separator
107
188
  @file_menu.append(ID::M_SAVEASBITMAP, "&Export to image...", "Export the chart to BMP file", Wx::ITEM_NORMAL)
108
189
  @file_menu.append_separator
109
- @file_menu.append(Wx::ID_PRINT, "&Print...\tCtrl+P", "Open print dialog", Wx::ITEM_NORMAL)
110
- @file_menu.append(Wx::ID_PREVIEW, "Print pre&view...\tAlt+P", "Open print preview window", Wx::ITEM_NORMAL)
190
+ mi = Wx::MenuItem.new(@file_menu, Wx::ID_PRINT, "&Print...\tCtrl+P", "Open print dialog")
191
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_PRINT, Wx::ART_MENU))
192
+ @file_menu.append mi
193
+ mi = Wx::MenuItem.new(@file_menu, Wx::ID_PREVIEW, "Print pre&view...\tAlt+P", "Open print preview window")
194
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FIND, Wx::ART_MENU))
195
+ @file_menu.append mi
111
196
  @file_menu.append(Wx::ID_PAGE_SETUP, "Pa&ge setup...", "Set print page properties", Wx::ITEM_NORMAL)
112
197
  @file_menu.append_separator
113
- @file_menu.append(Wx::ID_EXIT, "E&xit\tAlt+X", "Close application", Wx::ITEM_NORMAL)
114
-
115
- @edit_menu.append(Wx::ID_UNDO, "&Undo\tCtrl+Z", "Discard previous action", Wx::ITEM_NORMAL)
116
- @edit_menu.append(Wx::ID_REDO, "&Redo\tCtrl+Y", "Re-do previously discarded action", Wx::ITEM_NORMAL)
198
+ mi = Wx::MenuItem.new(@file_menu, Wx::ID_EXIT, "E&xit\tAlt+X", "Close application")
199
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_QUIT, Wx::ART_MENU))
200
+ @file_menu.append mi
201
+
202
+ mi = Wx::MenuItem.new(@edit_menu, Wx::ID_UNDO, "&Undo\tCtrl+Z", "Discard previous action")
203
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_UNDO, Wx::ART_MENU))
204
+ @edit_menu.append mi
205
+ mi = Wx::MenuItem.new(@edit_menu, Wx::ID_REDO, "&Redo\tCtrl+Y", "Re-do previously discarded action")
206
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_REDO, Wx::ART_MENU))
207
+ @edit_menu.append mi
117
208
  @edit_menu.append_separator
118
- @edit_menu.append(Wx::ID_SELECTALL, "Select &all\tCtrl+A", "Select all shapes", Wx::ITEM_NORMAL)
209
+ mi = Wx::MenuItem.new(@edit_menu, Wx::ID_SELECTALL, "Select &all\tCtrl+A", "Select all shapes")
210
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::MDAP::ART_SELECT_ALL, Wx::MDAP::ART_MATERIAL_DESIGN_OUTLINED,
211
+ Wx::ArtProvider.get_native_size_hint(Wx::ART_MENU)))
212
+ @edit_menu.append mi
119
213
  @edit_menu.append_separator
120
- @edit_menu.append(Wx::ID_COPY, "&Copy\tCtrl+C", "Copy shapes to the clipboard", Wx::ITEM_NORMAL)
121
- @edit_menu.append(Wx::ID_CUT, "Cu&t\tCtrl+X", "Cut shapes to the clipboard", Wx::ITEM_NORMAL)
122
- @edit_menu.append(Wx::ID_PASTE, "&Paste\tCtrl+V", "Paste shapes to the canvas", Wx::ITEM_NORMAL)
214
+ mi = Wx::MenuItem.new(@edit_menu, Wx::ID_COPY, "&Copy\tCtrl+C", "Copy shapes to the clipboard")
215
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_COPY, Wx::ART_MENU))
216
+ @edit_menu.append mi
217
+ mi = Wx::MenuItem.new(@edit_menu, Wx::ID_CUT, "Cu&t\tCtrl+X", "Cut shapes to the clipboard")
218
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_CUT, Wx::ART_MENU))
219
+ @edit_menu.append mi
220
+ mi = Wx::MenuItem.new(@edit_menu, Wx::ID_PASTE, "&Paste\tCtrl+V", "Paste shapes to the canvas")
221
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_PASTE, Wx::ART_MENU))
222
+ @edit_menu.append mi
223
+
224
+ submenu = Wx::Menu.new
225
+ submenu.append_radio_item(ID::T_TOOL, 'Design tool', 'Design tool')
226
+ submenu.append_radio_item(ID::T_RECTSHP, 'Rectangle', 'Rectangle')
227
+ submenu.append_radio_item(ID::T_SQUARESHP, 'Square', 'Square')
228
+ submenu.append_radio_item(ID::T_RNDRECTSHP, 'RoundRect', 'Rounded ractangle')
229
+ submenu.append_radio_item(ID::T_ELLIPSESHP, 'Ellipse', 'Ellipse')
230
+ submenu.append_radio_item(ID::T_CIRCLESHP, 'Circle', 'Circle')
231
+ submenu.append_radio_item(ID::T_DIAMONDSHP, 'Diamond', 'Diamond')
232
+ submenu.append_radio_item(ID::T_TEXTSHP, 'Text', 'Text')
233
+ submenu.append_radio_item(ID::T_EDITTEXTSHP, 'Editable Text', 'Editable Text')
234
+ submenu.append_radio_item(ID::T_BITMAPSHP, 'Bitmap', 'Bitmap')
235
+ submenu.append_radio_item(ID::T_GRIDSHP, 'Grid', 'Grid')
236
+ submenu.append_radio_item(ID::T_FLEXGRIDSHP, 'Flexible Grid', 'Flexible Grid')
237
+ submenu.append_radio_item(ID::T_VBOXSHP, 'Vertical Box', 'Vertical Box')
238
+ submenu.append_radio_item(ID::T_HBOXSHP, 'Horizontal Box', 'Horizontal Box')
239
+ submenu.append_radio_item(ID::T_LINESHP, 'Line', 'Connector Line')
240
+ submenu.append_radio_item(ID::T_CURVESHP, 'Curved Line', 'Curved Connector Line')
241
+ submenu.append_radio_item(ID::T_ORTHOSHP, 'Orthogonal Line', 'Orthogonal Connector Line')
242
+ submenu.append_radio_item(ID::T_RNDORTHOSHP, 'Rounded Orthogonal Line', 'Rounded Orthogonal Connector Line')
243
+ submenu.append_radio_item(ID::T_STANDALONELINESHP, 'Standalone Line', 'Standalone Line')
244
+ mi = Wx::MenuItem.new(@shape_menu, ID::M_SHAPE_LIST, 'Select shape', 'Select shape', Wx::ITEM_NORMAL, submenu)
245
+ @shape_menu.append(mi)
246
+ @shape_menu.append_separator
247
+ submenu = Wx::Menu.new
248
+ submenu.append_radio_item(ID::M_GRIDCOLS_1, '1 column', '1 column')
249
+ submenu.append_radio_item(ID::M_GRIDCOLS_2, '2 columns', '2 columns')
250
+ mi = submenu.append_radio_item(ID::M_GRIDCOLS_3, '3 columns', '3 columns')
251
+ mi.check(true)
252
+ submenu.append_radio_item(ID::M_GRIDCOLS_4, '4 columns', '4 columns')
253
+ submenu.append_radio_item(ID::M_GRIDCOLS_5, '5 columns', '5 columns')
254
+ @mi_gridcols_custom = submenu.append_radio_item(ID::M_GRIDCOLS_CUSTOM, 'Custom', 'Enter custom column number')
255
+ @mi_gridcol_nr = submenu.append(ID::M_GRIDCOLS_NR, 'Number of grid columns (3)', 'Select to change nr. of grid columns')
256
+ @mi_gridcol_nr.enable(false)
257
+ mi = Wx::MenuItem.new(@shape_menu, ID::M_GRID_COLUMNS, 'Set grid columns', 'Select number of grid columns', Wx::ITEM_NORMAL, submenu)
258
+ @shape_menu.append(mi)
123
259
 
124
260
  Wx::SF::AutoLayout.layout_algorithms.each_with_index do |la_name, i|
125
261
  @auto_layout_menu.append(ID::M_AUTOLAYOUT_FIRST + i, la_name)
126
262
  end
127
-
128
- @help_menu.append(Wx::ID_ABOUT, '&About...', 'About application...', Wx::ITEM_NORMAL)
129
263
 
130
- # set shape canvas and associate it with diagram
131
- @diagram = Wx::SF::Diagram.new
132
- @shape_canvas = FrameCanvas.new(@diagram, @canvas_panel, Wx::ID_ANY)
264
+ mi = Wx::MenuItem.new(@help_menu, Wx::ID_ABOUT, '&About...', 'About application...')
265
+ mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_INFORMATION, Wx::ART_MENU))
266
+ @help_menu.append mi
267
+
268
+ # set shape canvas and associate it with a new, empty, diagram
269
+ @shape_canvas = FrameCanvas.new(Wx::SF::Diagram.new, @canvas_panel, Wx::ID_ANY)
133
270
  @canvas_sizer.add(@shape_canvas, 1, Wx::EXPAND, 0)
134
271
  @canvas_panel.layout
135
272
  # enable using Wx::GraphicsContext by default
@@ -141,16 +278,7 @@ class MainFrame < Wx::Frame
141
278
  @thumb_frm.thumbnail.set_canvas(@shape_canvas)
142
279
  @thumb_frm.show
143
280
 
144
- # create colour picker
145
- if Wx::PLATFORM == 'WXMSW'
146
- @cpicker = Wx::ColourPickerCtrl.new(@tool_bar, ID::T_COLORPICKER, Wx::Colour.new(120, 120, 255), Wx::DEFAULT_POSITION, Wx::Size.new(22, 22))
147
- else
148
- @cpicker = Wx::ColourPickerCtrl.new(@tool_bar, ID::T_COLORPICKER, Wx::Colour.new(120, 120, 255), Wx::DEFAULT_POSITION, Wx::Size.new(28, 28))
149
- end
150
- @cpicker.set_tool_tip('Set hover color')
151
-
152
- # add m_pToolBar tools
153
- @tool_bar.set_tool_bitmap_size([16, 15])
281
+ # add tool_bar tools
154
282
  @tool_bar.add_tool(Wx::ID_NEW, 'New', Wx::ArtProvider.get_bitmap(Wx::ART_NEW, Wx::ART_MENU), 'New diagram')
155
283
  @tool_bar.add_tool(Wx::ID_OPEN, 'Load', Wx::ArtProvider.get_bitmap(Wx::ART_FILE_OPEN, Wx::ART_MENU), 'Open file...')
156
284
  @tool_bar.add_tool(Wx::ID_SAVE, 'Save', Wx::ArtProvider.get_bitmap(Wx::ART_FILE_SAVE, Wx::ART_MENU), 'Save file...')
@@ -165,13 +293,11 @@ class MainFrame < Wx::Frame
165
293
  @tool_bar.add_tool(Wx::ID_UNDO, 'Undo', Wx::ArtProvider.get_bitmap(Wx::ART_UNDO, Wx::ART_MENU), 'Undo')
166
294
  @tool_bar.add_tool(Wx::ID_REDO, 'Redo', Wx::ArtProvider.get_bitmap(Wx::ART_REDO, Wx::ART_MENU), 'Redo')
167
295
  @tool_bar.add_separator
168
- @tool_bar.add_check_tool(ID::T_GRID, 'Grid', Wx::Bitmap(:Grid), Wx::NULL_BITMAP, 'Show/hide grid')
169
- @tool_bar.add_check_tool(ID::T_SHADOW, 'Shadows', Wx::Bitmap(:Shadow), Wx::NULL_BITMAP, 'Show/hide shadows')
170
- @tool_bar.add_check_tool(ID::T_GC, 'Enhanced graphics context', Wx::Bitmap(:GC), Wx::NULL_BITMAP, 'Use enhanced graphics context (Wx::GraphicsContext)')
296
+ @tool_bar.add_tool(ID::T_SETTINGS, 'Settings', Wx::ArtProvider.get_bitmap(Wx::ART_HELP_SETTINGS, Wx::ART_MENU), 'Settings')
171
297
  @tool_bar.add_separator
172
298
  @tool_bar.add_radio_tool(ID::T_TOOL, 'Tool', Wx::Bitmap(:Tool), Wx::NULL_BITMAP, 'Design tool')
173
299
  @tool_bar.add_radio_tool(ID::T_RECTSHP, 'Rectangle', Wx::Bitmap(:Rect), Wx::NULL_BITMAP, 'Rectangle')
174
- @tool_bar.add_radio_tool(ID::T_SQUARESHP, 'Fixed rectangle', Wx::Bitmap(:FixedRect), Wx::NULL_BITMAP, 'Fixed rectangle')
300
+ @tool_bar.add_radio_tool(ID::T_SQUARESHP, 'Square', Wx::Bitmap(:FixedRect), Wx::NULL_BITMAP, 'Square')
175
301
  @tool_bar.add_radio_tool(ID::T_RNDRECTSHP, 'RoundRect', Wx::Bitmap(:RoundRect), Wx::NULL_BITMAP, 'Rounded rectangle')
176
302
  @tool_bar.add_radio_tool(ID::T_ELLIPSESHP, 'Ellipse', Wx::Bitmap(:Ellipse), Wx::NULL_BITMAP, 'Ellipse')
177
303
  @tool_bar.add_radio_tool(ID::T_CIRCLESHP, 'Circle', Wx::Bitmap(:Circle), Wx::NULL_BITMAP, 'Circle')
@@ -181,6 +307,8 @@ class MainFrame < Wx::Frame
181
307
  @tool_bar.add_radio_tool(ID::T_BITMAPSHP, 'Bitmap', Wx::Bitmap(:Bitmap), Wx::NULL_BITMAP, 'Bitmap')
182
308
  @tool_bar.add_radio_tool(ID::T_GRIDSHP, 'Grid shape', Wx::Bitmap(:Grid), Wx::NULL_BITMAP, 'Grid shape')
183
309
  @tool_bar.add_radio_tool(ID::T_FLEXGRIDSHP, 'Flexible grid shape', Wx::Bitmap(:FlexGrid), Wx::NULL_BITMAP, 'Flexible grid shape')
310
+ @tool_bar.add_radio_tool(ID::T_VBOXSHP, 'Vertical Box shape', Wx::Bitmap(:VBox), Wx::NULL_BITMAP, 'Vertical Box shape')
311
+ @tool_bar.add_radio_tool(ID::T_HBOXSHP, 'Horizontal Box shape', Wx::Bitmap(:HBox), Wx::NULL_BITMAP, 'Horizontal Box shape')
184
312
  @tool_bar.add_radio_tool(ID::T_LINESHP, 'Line', Wx::Bitmap(:Line), Wx::NULL_BITMAP, 'Polyline connection')
185
313
  @tool_bar.add_radio_tool(ID::T_CURVESHP, 'Curve', Wx::Bitmap(:Curve), Wx::NULL_BITMAP, 'Curve connection')
186
314
  @tool_bar.add_radio_tool(ID::T_ORTHOSHP, 'Ortho line', Wx::Bitmap(:OrthoLine), Wx::NULL_BITMAP, 'Orthogonal connection')
@@ -193,17 +321,17 @@ class MainFrame < Wx::Frame
193
321
  @tool_bar.add_tool(ID::T_ALIGN_BOTTOM, 'Align bottom', Wx::Bitmap(:AlignBottom), 'Align selected shapes to the bottom')
194
322
  @tool_bar.add_tool(ID::T_ALIGN_MIDDLE, 'Align middle', Wx::Bitmap(:AlignMiddle), 'Align selected shapes to the middle')
195
323
  @tool_bar.add_tool(ID::T_ALIGN_CENTER, 'Align center', Wx::Bitmap(:AlignCenter), 'Align selected shapes to the center')
196
- @tool_bar.add_separator
197
- @tool_bar.add_control(@cpicker)
198
324
  @tool_bar.realize
199
325
 
200
326
  @status_bar.set_status_text('Ready')
201
327
 
202
328
  # initialize data members
203
329
  @tool_mode = MODE::DESIGN
330
+ @grid_columns = 3
204
331
  @show_grid = true
205
332
  @show_shadows = false
206
333
 
334
+ set_size([1280, 800])
207
335
  centre
208
336
 
209
337
  # setup event handlers
@@ -226,6 +354,7 @@ class MainFrame < Wx::Frame
226
354
  evt_menu_range(ID::M_AUTOLAYOUT_FIRST, ID::M_AUTOLAYOUT_LAST, :on_auto_layout)
227
355
  evt_command_scroll(Wx::ID_ZOOM_FIT, :on_slider)
228
356
  evt_tool_range(ID::T_FIRST_TOOLMARKER, ID::T_LAST_TOOLMARKER, :on_tool)
357
+ evt_menu_range(ID::M_GRIDCOLS_1, ID::M_GRIDCOLS_NR, :on_grid_columns)
229
358
  evt_colourpicker_changed(ID::T_COLORPICKER, :on_hover_color)
230
359
  evt_update_ui(Wx::ID_COPY, :on_update_copy)
231
360
  evt_update_ui(Wx::ID_CUT, :on_update_cut)
@@ -234,19 +363,21 @@ class MainFrame < Wx::Frame
234
363
  evt_update_ui(Wx::ID_REDO, :on_update_redo)
235
364
  evt_update_ui_range(ID::T_FIRST_TOOLMARKER, ID::T_LAST_TOOLMARKER, :on_update_tool)
236
365
  evt_update_ui_range(ID::M_AUTOLAYOUT_FIRST, ID::M_AUTOLAYOUT_LAST, :on_update_auto_layout)
366
+ evt_update_ui(@mi_gridcol_nr, :on_update_gridcol_nr)
237
367
  evt_idle(:on_idle)
238
368
  end
239
369
 
240
370
  attr_accessor :tool_mode, :show_grid, :show_shadows
241
371
 
242
- attr_reader :zoom_slider
372
+ attr_reader :grid_columns, :zoom_slider
373
+
374
+ def diagram
375
+ @shape_canvas&.diagram
376
+ end
377
+ private :diagram
243
378
 
244
379
  def setup_frame
245
- if Wx::PLATFORM == 'WXMSW'
246
- set_size_hints([1024,700])
247
- else
248
- set_size_hints([1100,700])
249
- end
380
+ set_size_hints([1024, 640])
250
381
 
251
382
  @menu_bar = Wx::MenuBar.new(0)
252
383
  @file_menu = Wx::Menu.new
@@ -254,7 +385,10 @@ class MainFrame < Wx::Frame
254
385
 
255
386
  @edit_menu = Wx::Menu.new
256
387
  @menu_bar.append(@edit_menu, "&Edit")
257
-
388
+
389
+ @shape_menu = Wx::Menu.new
390
+ @menu_bar.append(@shape_menu, "&Shapes")
391
+
258
392
  @auto_layout_menu = Wx::Menu.new
259
393
  @menu_bar.append(@auto_layout_menu, "&AutoLayout")
260
394
 
@@ -262,22 +396,28 @@ class MainFrame < Wx::Frame
262
396
  @menu_bar.append(@help_menu, "&Help")
263
397
 
264
398
  set_menu_bar(@menu_bar)
265
-
266
- @tool_bar = create_tool_bar(Wx::TB_HORIZONTAL, Wx::ID_ANY)
267
- @tool_bar.realize
268
-
399
+
269
400
  @status_bar = create_status_bar(1, Wx::STB_SIZEGRIP, Wx::ID_ANY)
270
- main_sizer = Wx::FlexGridSizer.new(2, 1, 0, 0)
401
+ main_sizer = Wx::FlexGridSizer.new(3, 1, 0, 0)
271
402
  main_sizer.add_growable_col(0)
272
- main_sizer.add_growable_row(0)
403
+ main_sizer.add_growable_row(1)
273
404
  main_sizer.set_flexible_direction(Wx::BOTH)
274
405
  main_sizer.set_non_flexible_grow_mode(Wx::FLEX_GROWMODE_SPECIFIED)
275
-
406
+
407
+ tool_bar_panel = Wx::Panel.new(self, Wx::ID_ANY)
408
+ tool_bar_sizer = Wx::VBoxSizer.new
409
+ @tool_bar = Wx::ToolBar.new(tool_bar_panel, style: Wx::TB_HORIZONTAL | Wx::NO_BORDER | Wx::TB_FLAT)
410
+ @tool_bar.realize
411
+ tool_bar_sizer.add(@tool_bar, 0, Wx::EXPAND)
412
+ tool_bar_panel.sizer = tool_bar_sizer
413
+ tool_bar_panel.layout
414
+ main_sizer.add(tool_bar_panel, 0, Wx::EXPAND, 5)
415
+
276
416
  @canvas_panel = Wx::Panel.new(self, Wx::ID_ANY, style: Wx::TAB_TRAVERSAL)
277
417
  @canvas_panel.set_extra_style(Wx::WS_EX_BLOCK_EVENTS)
278
418
 
279
419
  @canvas_sizer = Wx::VBoxSizer.new
280
-
420
+
281
421
  @canvas_panel.set_sizer(@canvas_sizer)
282
422
  @canvas_panel.layout
283
423
  @canvas_sizer.fit(@canvas_panel)
@@ -299,8 +439,8 @@ class MainFrame < Wx::Frame
299
439
  protected
300
440
 
301
441
  def clean_up
302
- @diagram.set_shape_canvas(nil)
303
- @diagram.clear
442
+ diagram.set_shape_canvas(nil)
443
+ diagram.clear
304
444
 
305
445
  @thumb_frm.hide
306
446
  @thumb_frm.thumbnail.set_canvas(nil)
@@ -314,7 +454,7 @@ class MainFrame < Wx::Frame
314
454
  end
315
455
 
316
456
  def on_idle(_event)
317
- if @diagram.is_modified
457
+ if diagram.is_modified
318
458
  set_title('wxRuby ShapeFramework Demo (diagram is modified)')
319
459
  else
320
460
  set_title('wxRuby ShapeFramework Demo')
@@ -329,7 +469,7 @@ class MainFrame < Wx::Frame
329
469
  def on_new(_event)
330
470
  if Wx.message_box('Current chart will be lost. Do you want to proceed?',
331
471
  'wxRuby ShapeFramework', Wx::YES_NO | Wx::ICON_QUESTION) == Wx::YES
332
- @diagram.clear
472
+ diagram.clear
333
473
 
334
474
  @shape_canvas.clear_canvas_history
335
475
  @shape_canvas.save_canvas_state
@@ -339,24 +479,79 @@ class MainFrame < Wx::Frame
339
479
  end
340
480
 
341
481
  def on_save(_event)
342
- Wx::FileDialog(self, 'Save canvas to file...', Dir.getwd, '', 'JSON Files (*.json)|*.json', Wx::FD_SAVE | Wx::FD_OVERWRITE_PROMPT) do |dlg|
482
+ Wx.FileDialog(self, 'Save canvas to file...', __dir__, '', FILE_MASK, Wx::FD_SAVE) do |dlg|
483
+ dlg.set_filter_index(0)
484
+ dlg_hook = DiagramFileDialog.new(dlg, compact: true)
343
485
  if dlg.show_modal == Wx::ID_OK
344
- @shape_canvas.save_canvas(dlg.get_path)
345
-
346
- Wx.message_box("The chart has been saved to '#{dlg.get_path}'.", 'wxRuby ShapeFramework')
486
+ check_overwrite = Wx::PLATFORM != 'WXOSX'
487
+ begin
488
+ path = dlg.get_path.dup
489
+ selected_filter = dlg.get_filter_index
490
+ ext = File.extname(path)
491
+ if ext == '.' && !(Wx::PLATFORM == 'WXOSX' && File.exist?(path))
492
+ ext = ''
493
+ path = File.join(File.dirname(path), File.basename(path, '.*'))
494
+ check_overwrite = true
495
+ end
496
+ if ext.empty?
497
+ format = if selected_filter < 0 || selected_filter >= DiagramFileDialog::FORMATS.size
498
+ dlg_hook.format || :json
499
+ else
500
+ DiagramFileDialog::FORMATS[selected_filter].to_sym
501
+ end
502
+ if selected_filter < DiagramFileDialog::FORMATS.size && !(Wx::PLATFORM == 'WXOSX' && File.exist?(path))
503
+ # determine extension to provide
504
+ case format
505
+ when :json then path << '.json'
506
+ when :yaml then path << '.yaml'
507
+ when :xml then path << '.xml'
508
+ end
509
+ check_overwrite = true
510
+ end
511
+ else
512
+ format = case File.extname(dlg.get_path)
513
+ when '.json' then :json
514
+ when '.yaml', '.yml' then :yaml
515
+ when '.xml' then :xml
516
+ else
517
+ if selected_filter < 0 || selected_filter >= DiagramFileDialog::FORMATS.size
518
+ dlg_hook.format || :json
519
+ else
520
+ DiagramFileDialog::FORMATS[selected_filter].to_sym
521
+ end
522
+ end
523
+ end
524
+ if !check_overwrite || !File.exist?(path) ||
525
+ Wx.message_box("File '#{File.basename(path)}' already exists in folder '#{File.dirname(path)}'.\nDo you want to overwrite it?", 'Confirm', Wx::YES_NO) == Wx::YES
526
+ @shape_canvas.save_canvas(path, compact: dlg_hook.compact, format: format)
527
+
528
+ Wx.MessageDialog(self, "The chart has been saved to '#{path}'.", 'wxRuby ShapeFramework', Wx::OK | Wx::ICON_INFORMATION)
529
+ end
530
+ rescue Exception => ex
531
+ Wx.MessageDialog(self, "Failed to save the chart: #{ex.message}", 'wxRuby ShapeFramework', Wx::OK | Wx::ICON_ERROR)
532
+ end
347
533
  end
348
534
  end
349
535
  end
350
536
 
351
537
  def on_load(_event)
352
- Wx::FileDialog(self, 'Load canvas from file...', Dir.getwd, '', 'JSON Files (*.json)|*.json', Wx::FD_OPEN | Wx::FD_FILE_MUST_EXIST) do |dlg|
538
+ Wx.FileDialog(self, 'Load canvas from file...', __dir__, '', FILE_MASK, Wx::FD_OPEN | Wx::FD_FILE_MUST_EXIST) do |dlg|
539
+ dlg_hook = DiagramFileDialog.new(dlg)
353
540
  if dlg.show_modal == Wx::ID_OK
354
- @shape_canvas.load_canvas(dlg.get_path)
355
- @diagram = @shape_canvas.get_diagram
356
-
357
- @zoom_slider.set_value((@shape_canvas.get_scale*50).to_i)
358
-
359
- @cpicker.set_colour(@shape_canvas.get_hover_colour)
541
+ begin
542
+ format = case File.extname(dlg.get_path)
543
+ when '.json' then :json
544
+ when '.yaml', '.yml' then :yaml
545
+ when '.xml' then :xml
546
+ else
547
+ dlg_hook.format || :json
548
+ end
549
+ @shape_canvas.load_canvas(dlg.get_path, format: format)
550
+
551
+ @zoom_slider.set_value((@shape_canvas.get_scale*50).to_i)
552
+ rescue Exception => ex
553
+ Wx.MessageDialog(self, "Failed to load the chart: #{ex.message}", 'wxRuby ShapeFramework', Wx::OK | Wx::ICON_ERROR)
554
+ end
360
555
  end
361
556
  end
362
557
  end
@@ -448,30 +643,14 @@ class MainFrame < Wx::Frame
448
643
  @shape_canvas.abort_interactive_connection if @shape_canvas.get_mode == Wx::SF::ShapeCanvas::MODE::CREATECONNECTION
449
644
 
450
645
  case event.get_id
451
- when ID::T_GRID
452
- @show_grid = !@show_grid
453
- if @show_grid
454
- @shape_canvas.add_style(Wx::SF::ShapeCanvas::STYLE::GRID_SHOW)
455
- @shape_canvas.add_style(Wx::SF::ShapeCanvas::STYLE::GRID_USE)
456
- else
457
- @shape_canvas.remove_style(Wx::SF::ShapeCanvas::STYLE::GRID_SHOW)
458
- @shape_canvas.remove_style(Wx::SF::ShapeCanvas::STYLE::GRID_USE)
459
- end
460
- @shape_canvas.refresh(false)
461
-
462
- when ID::T_SHADOW
463
- @show_shadows = !@show_shadows
464
-
465
- @shape_canvas.show_shadows(@show_shadows, Wx::SF::ShapeCanvas::SHADOWMODE::ALL)
466
- # also shadows for topmost shapes only are allowed:
467
- # @shape_canvas.show_shadows(@show_shadows, Wx::SF::ShapeCanvas::SHADOWMODE::TOPMOST)
468
- @shape_canvas.refresh(false)
646
+ when ID::T_SETTINGS
647
+ Dialogs::WXSFPreferencesDialog(self, @shape_canvas)
469
648
 
470
649
  when ID::T_GC
471
650
  if Wx.has_feature?(:USE_GRAPHICS_CONTEXT)
472
651
  Wx::SF::ShapeCanvas.enable_gc(!Wx::SF::ShapeCanvas.gc_enabled?)
473
652
  # update all shapes in the manager
474
- @diagram.update_all
653
+ diagram.update_all
475
654
  # refresh shape canvas
476
655
  @shape_canvas.refresh(false)
477
656
  else
@@ -508,6 +687,12 @@ class MainFrame < Wx::Frame
508
687
  when ID::T_FLEXGRIDSHP
509
688
  @tool_mode = MODE::FLEXGRID
510
689
 
690
+ when ID::T_VBOXSHP
691
+ @tool_mode = MODE::VBOX
692
+
693
+ when ID::T_HBOXSHP
694
+ @tool_mode = MODE::HBOX
695
+
511
696
  when ID::T_LINESHP
512
697
  @tool_mode = MODE::LINE
513
698
 
@@ -552,6 +737,16 @@ class MainFrame < Wx::Frame
552
737
  end
553
738
  end
554
739
 
740
+ def on_grid_columns(event)
741
+ if event.get_id == ID::M_GRIDCOLS_CUSTOM || event.get_id == ID::M_GRIDCOLS_NR
742
+ n = Wx.get_number_from_user('Enter custom grid column number.', 'Nr. of columns:',
743
+ 'Grid columns', @grid_columns, 1, 100, self)
744
+ @grid_columns = n unless n <= 0
745
+ else
746
+ @grid_columns = 1 + event.get_id-ID::M_GRIDCOLS_1
747
+ end
748
+ end
749
+
555
750
  def on_hover_color(event)
556
751
  @shape_canvas.set_hover_colour(event.get_colour)
557
752
  end
@@ -578,9 +773,6 @@ class MainFrame < Wx::Frame
578
773
 
579
774
  def on_update_tool(event)
580
775
  case event.get_id
581
- when ID::T_GRID
582
- event.check(@show_grid)
583
-
584
776
  when ID::T_GC
585
777
  event.check(Wx::SF::ShapeCanvas.gc_enabled?)
586
778
 
@@ -614,6 +806,12 @@ class MainFrame < Wx::Frame
614
806
  when ID::T_FLEXGRIDSHP
615
807
  event.check(@tool_mode == MODE::FLEXGRID)
616
808
 
809
+ when ID::T_VBOXSHP
810
+ event.check(@tool_mode == MODE::VBOX)
811
+
812
+ when ID::T_HBOXSHP
813
+ event.check(@tool_mode == MODE::HBOX)
814
+
617
815
  when ID::T_LINESHP
618
816
  event.check(@tool_mode == MODE::LINE)
619
817
 
@@ -649,10 +847,22 @@ class MainFrame < Wx::Frame
649
847
  end
650
848
 
651
849
  def on_update_auto_layout(event)
652
- event.enable(!@diagram.empty?)
850
+ event.enable(!diagram.empty?)
851
+ end
852
+
853
+ def on_update_gridcol_nr(_event)
854
+ @mi_gridcol_nr.enable(@mi_gridcols_custom.checked?)
855
+ @mi_gridcol_nr.set_item_label("Number of grid columns (#{@grid_columns})")
653
856
  end
857
+
858
+ end
859
+
860
+ if Wx::PLATFORM == 'WXOSX' && !Wx.const_defined?(:OSX_FILEDIALOG_ALWAYS_SHOW_TYPES)
861
+ Wx::OSX_FILEDIALOG_ALWAYS_SHOW_TYPES = 'osx.openfiledialog.always-show-types'
654
862
  end
655
863
 
656
864
  Wx::App.run do
865
+ Wx::SystemOptions.set_option(Wx::OSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1) if Wx::PLATFORM == 'WXOSX'
866
+ Wx::ArtProvider.push(Wx::MDAP::MaterialDesignArtProvider.new)
657
867
  MainFrame.new(nil).show
658
868
  end