Using Material Design Art Provider for wxRuby3

The following example shows how to use Wx::MDAP::MaterialDesignArtProvider in a wxRuby3 application.

This example can be run with or without using Wx::MDAP::MaterialDesignArtProvider.
When using Wx::MDAP::MaterialDesignArtProvider the example also demonstrates how to optionally use custom default icon sizes and colours.

The following commandline switches are available to enable or disable options:

  • -u|--use-mdap
    directs the example to use Wx::MDAP::MaterialDesignArtProvider
  • -s|--small
    directs the example to use small (16x16) Material Design icons
  • -m|--medium
    directs the example to use medium (24x24) Material Design icons
  • -l|--large
    directs the example to use large (48x48) Material Design icons
  • -cCOLOUR|--colour=COLOUR
    directs the example to use COLOUR for Material Design icons; COLOUR can be specified as a colour name (like red or darkblue) or CSS (rgb(r,g,b), like rgb(255,0,0), or rgba(r,g,b,a) like rgba(255,0,0,0.333)) or HTML (#?????? like #FF0000) syntax.
  1# Copyright (c) 2023 M.J.N. Corino, The Netherlands
  2#
  3# This software is released under the MIT license.
  4
  5require 'wx'
  6require 'wx/mdap'
  7require 'optparse'
  8
  9class TestFrame < Wx::Frame
 10  def initialize(mdap = false)
 11    super(nil, title: "Frame #{mdap ? 'with' : 'without'} MaterialDesignArtProvider",
 12          size: [600, 400])
 13
 14    # Create the menu
 15    
 16    # To be able to optionally override system default icon mappings for stock ids like ID_NEW/ID_OPEN/ID_SAVE etc.
 17    # you need to explicitly set a bitmap for a menu item using Wx::ArtProvider and the standard Art Ids
 18    # matching these stock ids.
 19    # This way a custom art provider mapping the standard Art Ids like Wx::MDAP::MaterialDesignArtProvider can
 20    # override standard mappings if installed.
 21
 22    menuFile = Wx::Menu.new
 23    mi = Wx::MenuItem.new(menuFile, Wx::StandardID::ID_NEW, 'New')
 24    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_NEW, Wx::ART_MENU))
 25    menuFile.append(mi)
 26    mi = Wx::MenuItem.new(menuFile, Wx::StandardID::ID_OPEN, 'Open')
 27    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FILE_OPEN, Wx::ART_MENU))
 28    menuFile.append(mi)
 29    mi = Wx::MenuItem.new(menuFile, Wx::StandardID::ID_SAVE, 'Save')
 30    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FILE_SAVE, Wx::ART_MENU))
 31    menuFile.append(mi)
 32    mi = Wx::MenuItem.new(menuFile, Wx::StandardID::ID_SAVEAS, 'Save as...')
 33    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FILE_SAVE_AS, Wx::ART_MENU))
 34    menuFile.append(mi)
 35    menuFile.append_separator
 36    mi = Wx::MenuItem.new(menuFile, Wx::StandardID::ID_REFRESH, 'Refresh')
 37    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_REFRESH, Wx::ART_MENU))
 38    menuFile.append(mi)
 39    menuFile.append_separator
 40    mi = Wx::MenuItem.new(menuFile, Wx::StandardID::ID_PRINT, 'Print...')
 41    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_PRINT, Wx::ART_MENU))
 42    menuFile.append(mi)
 43    menuFile.append_separator
 44    mi = Wx::MenuItem.new(menuFile, Wx::StandardID::ID_CLOSE, 'Close')
 45    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_CLOSE, Wx::ART_MENU))
 46    menuFile.append(mi)
 47
 48    menuEdit = Wx::Menu.new
 49    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_CUT, 'Cut')
 50    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_CUT, Wx::ART_MENU))
 51    menuEdit.append(mi)
 52    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_COPY, 'Copy')
 53    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_COPY, Wx::ART_MENU))
 54    menuEdit.append(mi)
 55    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_PASTE, 'Paste')
 56    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_PASTE, Wx::ART_MENU))
 57    menuEdit.append(mi)
 58    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_DELETE, 'Delete')
 59    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_DELETE, Wx::ART_MENU))
 60    menuEdit.append(mi)
 61    menuEdit.append_separator
 62    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_UNDO, 'Undo')
 63    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_UNDO, Wx::ART_MENU))
 64    menuEdit.append(mi)
 65    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_REDO, 'Redo')
 66    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_REDO, Wx::ART_MENU))
 67    menuEdit.append(mi)
 68    menuEdit.append_separator
 69    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_FIND, 'Find')
 70    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FIND, Wx::ART_MENU))
 71    menuEdit.append(mi)
 72    mi = Wx::MenuItem.new(menuEdit, Wx::StandardID::ID_REPLACE, 'Replace')
 73    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FIND_AND_REPLACE, Wx::ART_MENU))
 74    menuEdit.append(mi)
 75
 76    menuHelp = Wx::Menu.new
 77    mi = Wx::MenuItem.new(menuHelp, Wx::StandardID::ID_ABOUT, 'About')
 78    mi.set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_INFORMATION, Wx::ART_MENU))
 79    menuHelp.append(mi)
 80
 81    menuBar = Wx::MenuBar.new
 82    menuBar.append(menuFile, "&File")
 83    menuBar.append(menuEdit, "&Edit")
 84    menuBar.append(menuHelp, "&Help")
 85    set_menu_bar(menuBar)
 86
 87    # Create a panel to place the toolbar in (a toolbar could also be attached directly to a Wx::Frame but this
 88    # has unfortunate effects with the MacOSX native toolbar integration in the app title bar which does not work
 89    # for small icons and, IMO, is not very pretty). 
 90    panel = Wx::Panel.new(self)
 91
 92    panel_szr = Wx::VBoxSizer.new
 93    
 94    # Create the toolbar
 95    tbar = Wx::ToolBar.new(panel, style: Wx::TB_HORIZONTAL | Wx::NO_BORDER | Wx::TB_FLAT)
 96    tbar.tool_bitmap_size = mdap ? Wx::MDAP::MaterialDesignArtProvider.get_default_size(Wx::ART_TOOLBAR) : [ 16, 16 ]
 97    tbar.add_tool(Wx::StandardID::ID_NEW, 'New', Wx::ArtProvider.get_bitmap(Wx::ART_NEW, Wx::ART_TOOLBAR), 'Create a new file')
 98    tbar.add_tool(Wx::StandardID::ID_OPEN, 'New', Wx::ArtProvider.get_bitmap(Wx::ART_FILE_OPEN, Wx::ART_TOOLBAR), 'Open a file')
 99    tbar.add_tool(Wx::StandardID::ID_SAVE, 'Save', Wx::ArtProvider.get_bitmap(Wx::ART_FILE_SAVE, Wx::ART_TOOLBAR), 'Save the file')
100    tbar.add_separator
101    tbar.add_tool(Wx::StandardID::ID_UNDO, 'Undo', Wx::ArtProvider.get_bitmap(Wx::ART_UNDO, Wx::ART_TOOLBAR), 'Undo change')
102    tbar.add_tool(Wx::StandardID::ID_REDO, 'Redo', Wx::ArtProvider.get_bitmap(Wx::ART_REDO, Wx::ART_TOOLBAR), 'Redo change')
103    tbar.add_separator
104    tbar.add_tool(Wx::StandardID::ID_COPY, 'Copy', Wx::ArtProvider.get_bitmap(Wx::ART_COPY, Wx::ART_TOOLBAR), 'Copy selection')
105    tbar.add_tool(Wx::StandardID::ID_CUT, 'Cut', Wx::ArtProvider.get_bitmap(Wx::ART_CUT, Wx::ART_TOOLBAR), 'Cut selection')
106    tbar.add_tool(Wx::StandardID::ID_PASTE, 'Paste', Wx::ArtProvider.get_bitmap(Wx::ART_PASTE, Wx::ART_TOOLBAR), 'Paste selection')
107    tbar.add_separator
108    tbar.add_tool(Wx::StandardID::ID_FIND, 'Find', Wx::ArtProvider.get_bitmap(Wx::ART_FIND, Wx::ART_TOOLBAR), 'Show Find Dialog')
109    tbar.add_tool(Wx::StandardID::ID_REPLACE, 'Replace', Wx::ArtProvider.get_bitmap(Wx::ART_FIND_AND_REPLACE, Wx::ART_TOOLBAR), 'Show Replace Dialog')
110    tbar.realize
111
112    panel_szr.add(tbar, 0, Wx::Stretch::EXPAND)
113    
114    panel.set_sizer(panel_szr)
115    
116    evt_menu(Wx::StandardID::ID_CLOSE) { close(true) }
117  end
118
119end
120
121class TestApp < Wx::App
122  def initialize
123    super
124    
125    @mdap = false
126    @colour = nil
127    @size = nil
128    
129    # parse commandline arguments
130    parse_args
131  end
132
133  def on_init
134    # Setup MaterialDesignArtProvider use if needed
135    Wx::ArtProvider.push(Wx::MDAP::MaterialDesignArtProvider.new) if @mdap
136    Wx::MDAP::MaterialDesignArtProvider.use_art_colour(@colour) if @mdap && @colour
137    Wx::MDAP::MaterialDesignArtProvider.set_default_size(Wx::ART_MENU, @size) if @mdap && @size
138    Wx::MDAP::MaterialDesignArtProvider.set_default_size(Wx::ART_TOOLBAR, @size) if @mdap && @size
139    
140    # create and show the test frame
141    TestFrame.new(@mdap).show
142  end
143
144  protected
145
146  def parse_args
147    opts = OptionParser.new
148    opts.on('-u', '--use-mdap',
149            'Use MaterialDesignArtProvider') { |v| @mdap = true }
150    opts.on('-cCOLOUR', '--colour=COLOUR',
151            'Use COLOUR for MaterialDesign art.') { |v| @colour = v }
152    opts.on('-s', '--small',
153            'Use small size for MaterialDesign art.') { |v| @size = [16,16] }
154    opts.on('-m', '--medium',
155            'Use medium size for MaterialDesign art.') { |v| @size = [24,24] }
156    opts.on('-l', '--large',
157            'Use large size for MaterialDesign art.') { |v| @size = [48,48] }
158    opts.order!(ARGV) rescue ($stderr.puts "#{$!}\n#{$!.backtrace.join("\n")}"; exit(1))
159  end
160end
161
162# run the application
163TestApp.run