# Copyright (c) 2023 M.J.N. Corino, The Netherlands # # This software is released under the MIT license. ### # PropertyGrid extended sample ### require 'wx' require_relative './propgrid_minimal' module PropGrid # ----------------------------------------------------------------------- # WxSampleMultiButtonEditor # A sample editor class that has multiple buttons. # ----------------------------------------------------------------------- class WxSampleMultiButtonEditor < Wx::PG::PGTextCtrlEditor def initialize super end def create_controls(propGrid, property, pos, sz) # Create and populate buttons-subwindow buttons = Wx::PG::PGMultiButton.new(propGrid, sz) # Add two regular buttons buttons.add('...') buttons.add('A') # Add a bitmap button buttons.add(Wx::ArtProvider::get_bitmap(Wx::ART_FOLDER)) # Create the 'primary' editor control (textctrl in this case) primary, _ = super(propGrid, property, pos, buttons.primary_size) # Finally, move buttons-subwindow to correct position and make sure # returned Wx::PG::PGWindowList contains our custom button list. buttons.finalize(propGrid, pos) [primary, buttons] end def on_event(propGrid, property, ctrl, event) if event.event_type == Wx::EVT_BUTTON buttons = propGrid.get_editor_control_secondary if event.id == buttons.button_id(0) # Do something when the first button is pressed Wx::log_info('First button pressed') return false # Return false since value did not change end if event.id == buttons.get_button_id(1) # Do something when the second button is pressed Wx.message_box('Second button pressed') return false # Return false since value did not change end if event.id == buttons.button_id(2) # Do something when the third button is pressed Wx.message_box('Third button pressed') return false # Return false since value did not change end end super(propGrid, property, ctrl, event) end end # class WxSampleMultiButtonEditor if Wx.has_feature?(:USE_VALIDATORS) class WxInvalidWordValidator < Wx::Validator def initialize(invalidWord) super() @invalidWord = invalidWord end def clone return WxInvalidWordValidator.new(@invalidWord) end def validate(parent_) tc = get_window raise 'validator window must be wxTextCtrl' unless Wx::TextCtrl === tc val = tc.value return true unless val.index(@invalidWord) Wx.message_box("%s is not allowed word" % @invalidWord, "Validation Failure") false end end # class WxInvalidWordValidator end # ----------------------------------------------------------------------- # WxVectorProperty # ----------------------------------------------------------------------- class WxVectorProperty < Wx::PG::PGProperty WxVector3f = Struct.new(:x, :y, :z) do |klass| def initialize self.x = self.y = self.z = 0.0 end end def initialize(label = Wx::PG::PG_LABEL, name = Wx::PG::PG_LABEL, value = WxVector3f.new) super(label, name) self.value = value add_private_child(Wx::PG::FloatProperty.new("X",Wx::PG::PG_LABEL, value.x)) add_private_child(Wx::PG::FloatProperty.new("Y",Wx::PG::PG_LABEL, value.y)) add_private_child(Wx::PG::FloatProperty.new("Z",Wx::PG::PG_LABEL, value.z)) end def child_changed(thisValue, childIndex, childValue) vector = thisValue.object; case childIndex when 0 vector.x = childValue.to_f when 1 vector.y = childValue.to_f when 2 vector.z = childValue.to_f end Wx::Variant.new(vector) end def refresh_children return if get_child_count == 0 vector = self.value_.object item(0).value = vector.x item(1).value = vector.y item(2).value = vector.z end end # class WxVectorProperty # ----------------------------------------------------------------------- # Wx::PG::TriangleProperty # ----------------------------------------------------------------------- class WxTriangleProperty < Wx::PG::PGProperty WxTriangle = Struct.new(:a, :b, :c) do |klass| def initialize self.a = WxVectorProperty::WxVector3f.new self.b = WxVectorProperty::WxVector3f.new self.c = WxVectorProperty::WxVector3f.new end end def initialize(label = Wx::PG::PG_LABEL, name = Wx::PG::PG_LABEL, value = WxTriangle.new) super(label, name) self.value = value add_private_child(WxVectorProperty.new("A", Wx::PG::PG_LABEL, value.a.dup)) add_private_child(WxVectorProperty.new("B", Wx::PG::PG_LABEL, value.b.dup)) add_private_child(WxVectorProperty.new("C", Wx::PG::PG_LABEL, value.c.dup)) end def child_changed(thisValue, childIndex, childValue) triangle = thisValue.object.dup vector = childValue.object.dup case childIndex when 0 triangle.a = vector when 1 triangle.b = vector when 2 triangle.c = vector end Wx::Variant.new(triangle) end def refresh_children return if get_child_count == 0 triangle = self.value_.object item(0).value = triangle.a item(1).value = triangle.b item(2).value = triangle.c end end # class WxTriangleProperty # ----------------------------------------------------------------------- # wxSingleChoiceDialogAdapter (Wx::PG::PGEditorDialogAdapter sample) # ----------------------------------------------------------------------- class WxSingleChoiceDialogAdapter < Wx::PG::PGEditorDialogAdapter def initialize(choices) super() @choices = choices end def do_show_dialog(propGrid_, property_) s = Wx.get_single_choice("Message", "Caption", @choices.labels) unless s.empty? value = s return true end return false end end # class WxSingleChoiceDialogAdapter class WxSingleChoiceProperty < Wx::PG::StringProperty def initialize(label, name = Wx::PG::PG_LABEL, value = '') super(label, name, value) # Prepare choices @choices = Wx::PG::PGChoices.new @choices.add("Cat") @choices.add("Dog") @choices.add("Gibbon") @choices.add("Otter") end # Set editor to have button def do_get_editor_class Wx::PG::PG_EDITOR_TEXT_CTRL_AND_BUTTON end # Set what happens on button click def get_editor_dialog WxSingleChoiceDialogAdapter.new(@choices) end end # class SingleChoiceProperty # # Test customizing wxColourProperty via subclassing # # * Includes custom colour entry. # * Includes extra custom entry. # class MyColourProperty < Wx::PG::ColourProperty def initialize(label = Wx::PG::PG_LABEL, name = Wx::PG::PG_LABEL, value = Wx::WHITE ) super(label, name, value) self.choices = Wx::PG::PGChoices.new(%w[White Black Red Green Blue Custom None]) set_index(0) self.value = value end def get_colour(index) case index when 0 return Wx::WHITE when 1 return Wx::BLACK when 2 return Wx::RED when 3 return Wx::GREEN when 4 return Wx::BLUE when 5 # Return current colour for the custom entry if get_index == get_custom_colour_index return self.value_.colour unless self.value_.null? else return Wx::WHITE end end Wx::Colour.new end def colour_to_string(col, index, argFlags = 0) return '' if index == (self.choices.get_count-1) super(col, index, argFlags) end def get_custom_colour_index self.choices.get_count-2 end end module ID include Wx::IDHelper PGID = self.next_id ABOUT = self.next_id QUIT = self.next_id APPENDPROP = self.next_id APPENDCAT = self.next_id INSERTPROP = self.next_id INSERTCAT = self.next_id ENABLE = self.next_id SETREADONLY = self.next_id HIDE = self.next_id BOOL_CHECKBOX = self.next_id DELETE = self.next_id DELETER = self.next_id DELETEALL = self.next_id UNSPECIFY = self.next_id ITERATE1 = self.next_id ITERATE2 = self.next_id ITERATE3 = self.next_id ITERATE4 = self.next_id CLEARMODIF = self.next_id FREEZE = self.next_id DUMPLIST = self.next_id COLOURSCHEME1 = self.next_id COLOURSCHEME2 = self.next_id COLOURSCHEME3 = self.next_id CATCOLOURS = self.next_id SETBGCOLOUR = self.next_id SETBGCOLOURRECUR = self.next_id STATICLAYOUT = self.next_id POPULATE1 = self.next_id POPULATE2 = self.next_id COLLAPSE = self.next_id COLLAPSEALL = self.next_id GETVALUES = self.next_id SETVALUES = self.next_id SETVALUES2 = self.next_id RUNTESTFULL = self.next_id RUNTESTPARTIAL = self.next_id FITCOLUMNS = self.next_id CHANGEFLAGSITEMS = self.next_id TESTINSERTCHOICE = self.next_id TESTDELETECHOICE = self.next_id INSERTPAGE = self.next_id REMOVEPAGE = self.next_id SETSPINCTRLEDITOR = self.next_id SETPROPERTYVALUE = self.next_id TESTREPLACE = self.next_id SETCOLUMNS = self.next_id SETVIRTWIDTH = self.next_id SETPGDISABLED = self.next_id TESTXRC = self.next_id ENABLECOMMONVALUES = self.next_id SELECTSTYLE = self.next_id SAVESTATE = self.next_id RESTORESTATE = self.next_id RUNMINIMAL = self.next_id ENABLELABELEDITING = self.next_id VETOCOLDRAG = self.next_id ONEXTENDEDKEYNAV = self.next_id SHOWPOPUP = self.next_id POPUPGRID = self.next_id if Wx.has_feature?(:USE_HEADERCTRL) SHOWHEADER = self.next_id end COLOURSCHEME4 = self.next_id end # # Handle events of the third page here. class WxMyPropertyGridPage < Wx::PG::PropertyGridPage def initialize super evt_pg_selected(Wx::ID_ANY, :on_property_select) evt_pg_changing(Wx::ID_ANY, :on_property_changing) evt_pg_changed(Wx::ID_ANY, :on_property_change) evt_pg_page_changed(Wx::ID_ANY, :on_page_change) end # Return false here to indicate unhandled events should be # propagated to manager's parent, as normal. def is_handling_all_events; false; end def do_insert(parent, index, property) super(parent,index,property) end def on_property_select(event) Wx.log_debug("WxMyPropertyGridPage#on_property_select('%s' is %s", event.property.get_name, (property_selected?(event.property) ? "selected": "unselected")) end def on_property_changing(event) Wx.log_verbose("WxMyPropertyGridPage#on_property_change('%s', to value '%s')", event.property.get_name, event.property.get_displayed_string) end def on_property_change(event) Wx.log_verbose("WxMyPropertyGridPage#on_property_changing('%s', to value '%s')", event.property.get_name, event.value.to_s) end def on_page_change(event) Wx.log_debug("WxMyPropertyGridPage#on_page_change()") end end # class WxMyPropertyGridPage class WxPGKeyHandler < Wx::EvtHandler def initialize super evt_key_down :on_key_event end def on_key_event(event) Wx.message_box("%i" % event.get_key_code) event.skip end end class PropertyGridPopup < Wx::PopupWindow private def get_real_root(grid) property = grid.root property ? grid.get_first_child(property) : nil end private def get_column_widths(grid, root) state = grid.get_state width = [0,0,0] minWidths = [ state.get_column_min_width(0), state.get_column_min_width(1), state.get_column_min_width(2) ] root.child_count.times do |ii| p = root.item(ii) width[0] = [width[0], state.get_column_full_width(p, 0)].max width[1] = [width[1], state.get_column_full_width(p, 1)].max width[2] = [width[2], state.get_column_full_width(p, 2)].max end root.child_count.times do |ii| p = root.item(ii) if p.is_expanded w = get_column_widths(grid, p) width[0] = [width[0], w[0]].max width[1] = [width[1], w[1]].max width[2] = [width[2], w[2]].max end end width[0] = [width[0], minWidths[0]].max width[1] = [width[1], minWidths[1]].max width[2] = [width[2], minWidths[2]].max width end private def set_popup_min_size(grid) p = get_real_root(grid) first = grid.get_first(Wx::PG::PG_ITERATE_ALL) last = grid.get_last_item(Wx::PG::PG_ITERATE_DEFAULT) rect = grid.get_property_rect(first, last) height = rect.height + 2 * grid.get_vertical_spacing # add some height when the root item is collapsed, # this is needed to prevent the vertical scroll from showing unless grid.is_property_expanded(p) height += 2 * grid.get_vertical_spacing end width = get_column_widths(grid, grid.root) rect.width = width.sum minWidth = (Wx::SystemSettings.get_metric(Wx::SYS_SCREEN_X, grid.get_parent)*3)/2 minHeight = (Wx::SystemSettings.get_metric(Wx::SYS_SCREEN_Y, grid.get_parent)*3)/2 size = [[minWidth, rect.width + grid.get_margin_width].min, [minHeight, height].min] grid.set_min_size(size) proportions = [ (100.0*width[0]/size[0]).round, (100.0*width[1]/size[0]).round ] proportions << [100 - proportions[0] - proportions[1], 0].max grid.set_column_proportion(0, proportions[0]) grid.set_column_proportion(1, proportions[1]) grid.set_column_proportion(2, proportions[2]) grid.reset_column_sizes(true) end def initialize(parent) super(parent, Wx::BORDER_NONE|Wx::WANTS_CHARS|Wx::PU_CONTAINS_CONTROLS) @panel = Wx::ScrolledWindow.new(self, Wx::ID_ANY, size: Wx::Size.new(200, 200)) @grid = Wx::PG::PropertyGrid.new(@panel, ID::POPUPGRID, size: [400,400], style: Wx::PG::PG_SPLITTER_AUTO_CENTER) @grid.set_column_count(3) prop = @grid.append(Wx::PG::StringProperty.new("test_name", Wx::PG::PG_LABEL, "test_value")) @grid.set_property_attribute(prop, Wx::PG::PG_ATTR_UNITS, "type") prop1 = @grid.append_in(prop, Wx::PG::StringProperty.new("sub_name1", Wx::PG::PG_LABEL, "sub_value1")) @grid.append_in(prop1, Wx::PG::SystemColourProperty.new("Cell Colour", Wx::PG::PG_LABEL, @grid.grid.get_cell_background_colour)) prop2 = @grid.append_in(prop, Wx::PG::StringProperty.new("sub_name2", Wx::PG::PG_LABEL, "sub_value2")) @grid.append_in(prop2, Wx::PG::StringProperty.new("sub_name21", Wx::PG::PG_LABEL, "sub_value21")) arrdbl = [-1.0, -0.5, 0.0, 0.5, 1.0] @grid.append_in(prop, WxArrayDoubleProperty.new("ArrayDoubleProperty", Wx::PG::PG_LABEL, arrdbl)) @grid.append_in(prop, Wx::PG::FontProperty.new("Font", Wx::PG::PG_LABEL)) @grid.append_in(prop2, Wx::PG::StringProperty.new("sub_name22", Wx::PG::PG_LABEL, "sub_value22")) @grid.append_in(prop2, Wx::PG::StringProperty.new("sub_name23", Wx::PG::PG_LABEL, "sub_value23")) prop2.set_expanded(false) set_popup_min_size(@grid) @sizer = Wx::BoxSizer.new(Wx::VERTICAL) @sizer.add(@grid, Wx::SizerFlags.new(0).expand.border(Wx::ALL, 0)) @panel.set_auto_layout(true) @panel.set_sizer(@sizer) @sizer.fit(@panel) @sizer.fit(self) evt_pg_item_collapsed ID::POPUPGRID, :on_collapse evt_pg_item_expanded ID::POPUPGRID, :on_expand end def on_collapse(event) Wx.log_message("OnCollapse") fit end def on_expand(event) Wx.log_message("OnExpand") fit end def fit set_popup_min_size(@grid) @sizer.fit(@panel) pos = get_screen_position size = @panel.get_screen_rect.size set_size(pos.x, pos.y, size.width, size.height) end end class FormMain < Wx::Frame FS_WINDOWSTYLE_LABELS = %w[ wxSIMPLE_BORDER wxDOUBLE_BORDER wxSUNKEN_BORDER wxRAISED_BORDER wxNO_BORDER wxTRANSPARENT_WINDOW wxTAB_TRAVERSAL wxWANTS_CHARS wxVSCROLL wxALWAYS_SHOW_SB wxCLIP_CHILDREN wxFULL_REPAINT_ON_RESIZE] FS_WINDOWSTYLE_VALUES = [ Wx::SIMPLE_BORDER, Wx::DOUBLE_BORDER, Wx::SUNKEN_BORDER, Wx::RAISED_BORDER, Wx::NO_BORDER, Wx::TRANSPARENT_WINDOW, Wx::TAB_TRAVERSAL, Wx::WANTS_CHARS, Wx::VSCROLL, Wx::ALWAYS_SHOW_SB, Wx::CLIP_CHILDREN, Wx::FULL_REPAINT_ON_RESIZE ] FS_FRAMESTYLE_LABELS = %w[ wxCAPTION wxMINIMIZE wxMAXIMIZE wxCLOSE_BOX wxSTAY_ON_TOP wxSYSTEM_MENU wxRESIZE_BORDER wxFRAME_TOOL_WINDOW wxFRAME_NO_TASKBAR wxFRAME_FLOAT_ON_PARENT wxFRAME_SHAPED] FS_FRAMESTYLE_VALUES = [ Wx::CAPTION, Wx::MINIMIZE, Wx::MAXIMIZE, Wx::CLOSE_BOX, Wx::STAY_ON_TOP, Wx::SYSTEM_MENU, Wx::RESIZE_BORDER, Wx::FRAME_TOOL_WINDOW, Wx::FRAME_NO_TASKBAR, Wx::FRAME_FLOAT_ON_PARENT, Wx::FRAME_SHAPED ] def initialize(title, pos, size) super(nil, title: title, pos: pos, size: size, style: (Wx::MINIMIZE_BOX|Wx::MAXIMIZE_BOX|Wx::RESIZE_BORDER|Wx::SYSTEM_MENU| Wx::CAPTION|Wx::TAB_TRAVERSAL|Wx::CLOSE_BOX)) @propGridManager = nil @propGrid = nil @hasHeader = false @labelEditingEnabled = false @combinedFlags = Wx::PG::PGChoices.new self.icon = Wx::Icon.new(local_icon_file('../sample.xpm')) centre # This is default in wxRuby # if Wx.has_feature?(:USE_IMAGE) # # This is here to really test the Wx::PG::ImageFileProperty. # wxInitAllImageHandlers() # end # Create menu bar menuFile = Wx::Menu.new('', Wx::MENU_TEAROFF) menuTry = Wx::Menu.new menuTools1 = Wx::Menu.new menuTools2 = Wx::Menu.new menuHelp = Wx::Menu.new menuHelp.append(ID::ABOUT, '&About', 'Show about dialog') if Wx::PLATFORM == 'WXOSX' Wx.get_app.mac_about_menu_itemid = ID::ABOUT end menuTools1.append(ID::APPENDPROP, 'Append New Property') menuTools1.append(ID::APPENDCAT, "Append New Category\tCtrl-S") menuTools1.append_separator menuTools1.append(ID::INSERTPROP, "Insert New Property\tCtrl-I") menuTools1.append(ID::INSERTCAT, "Insert New Category\tCtrl-W") menuTools1.append_separator menuTools1.append(ID::DELETE, 'Delete Selected') menuTools1.append(ID::DELETER, 'Delete Random') menuTools1.append(ID::DELETEALL, 'Delete All') menuTools1.append_separator menuTools1.append(ID::POPULATE1, 'Populate with Standard Items') menuTools1.append(ID::POPULATE2, 'Populate with Library Configuration') menuTools1.append_separator menuTools1.append(ID::SETBGCOLOUR, 'Set Bg Colour') menuTools1.append(ID::SETBGCOLOURRECUR, 'Set Bg Colour (Recursively)') menuTools1.append(ID::UNSPECIFY, 'Set Value to Unspecified') menuTools1.append_separator @itemEnable = menuTools1.append(ID::ENABLE, 'Enable', 'Toggles item\'s enabled state.') @itemEnable.enable(false) menuTools1.append(ID::HIDE, 'Hide', 'Hides a property') menuTools1.append(ID::SETREADONLY, 'Set as Read-Only', 'Set property as read-only') menuTools2.append(ID::ITERATE1, 'Iterate Over Properties') menuTools2.append(ID::ITERATE2, 'Iterate Over Visible Items') menuTools2.append(ID::ITERATE3, 'Reverse Iterate Over Properties') menuTools2.append(ID::ITERATE4, 'Iterate Over Categories') menuTools2.append_separator menuTools2.append(ID::ONEXTENDEDKEYNAV, 'Extend Keyboard Navigation', 'This will set Enter to navigate to next property, '+ 'and allows arrow keys to navigate even when in '+ 'editor control.') menuTools2.append_separator menuTools2.append(ID::SETPROPERTYVALUE, 'Set Property Value') menuTools2.append(ID::CLEARMODIF, 'Clear Modified Status', 'Clears Wx::PG::PG_MODIFIED flag from all properties.') menuTools2.append_separator @itemFreeze = menuTools2.append_check_item(ID::FREEZE, 'Freeze', 'Disables painting, auto-sorting, etc.') menuTools2.append_separator menuTools2.append(ID::DUMPLIST, 'Display Values as wxVariant List', 'Tests GetAllValues method and wxVariant conversion.') menuTools2.append_separator menuTools2.append(ID::GETVALUES, 'Get Property Values', 'Stores all property values.') menuTools2.append(ID::SETVALUES, 'Set Property Values', 'Reverts property values to those last stored.') menuTools2.append(ID::SETVALUES2, 'Set Property Values 2', 'Adds property values that should not initially be as items (so new items are created).') menuTools2.append_separator menuTools2.append(ID::SAVESTATE, 'Save Editable State') menuTools2.append(ID::RESTORESTATE, 'Restore Editable State') menuTools2.append_separator menuTools2.append(ID::ENABLECOMMONVALUES, 'Enable Common Value', 'Enable values that are common to all properties, for selected property.') menuTools2.append_separator menuTools2.append(ID::COLLAPSE, 'Collapse Selected') menuTools2.append(ID::COLLAPSEALL, 'Collapse All') menuTools2.append_separator menuTools2.append(ID::INSERTPAGE, 'Add Page') menuTools2.append(ID::REMOVEPAGE, 'Remove Page') menuTools2.append_separator menuTools2.append(ID::FITCOLUMNS, 'Fit Columns') @itemVetoDragging = menuTools2.append_check_item(ID::VETOCOLDRAG, 'Veto Column Dragging') menuTools2.append_separator menuTools2.append(ID::CHANGEFLAGSITEMS, 'Change Children of FlagsProp') menuTools2.append_separator menuTools2.append(ID::TESTINSERTCHOICE, 'Test InsertPropertyChoice') menuTools2.append(ID::TESTDELETECHOICE, 'Test DeletePropertyChoice') menuTools2.append_separator menuTools2.append(ID::SETSPINCTRLEDITOR, 'Use SpinCtrl Editor') menuTools2.append(ID::TESTREPLACE, 'Test ReplaceProperty') menuTry.append(ID::SELECTSTYLE, 'Set Window Style', 'Select window style flags used by the grid.') menuTry.append_check_item(ID::ENABLELABELEDITING, 'Enable label editing', 'This calls wxPropertyGrid::MakeColumnEditable(0)') menuTry.check(ID::ENABLELABELEDITING, @labelEditingEnabled) if Wx.has_feature?(:USE_HEADERCTRL) menuTry.append_check_item(ID::SHOWHEADER, 'Enable header', 'This calls wxPropertyGridManager::ShowHeader()') menuTry.check(ID::SHOWHEADER, @hasHeader) end # USE_HEADERCTRL menuTry.append_separator menuTry.append_radio_item(ID::COLOURSCHEME1, 'Standard Colour Scheme') menuTry.append_radio_item(ID::COLOURSCHEME2, 'White Colour Scheme') menuTry.append_radio_item(ID::COLOURSCHEME3, '.NET Colour Scheme') menuTry.append_radio_item(ID::COLOURSCHEME4, 'Cream Colour Scheme') menuTry.append_separator @itemCatColours = menuTry.append_check_item(ID::CATCOLOURS, 'Category Specific Colours', 'Switches between category-specific cell colours and default scheme (actually done using SetPropertyTextColour and SetPropertyBackgroundColour).') menuTry.append_separator menuTry.append_check_item(ID::STATICLAYOUT, 'Static Layout', 'Switches between user-modifiable and static layouts.') menuTry.append_check_item(ID::BOOL_CHECKBOX, 'Render Boolean values as checkboxes', 'Renders Boolean values as checkboxes') menuTry.append(ID::SETCOLUMNS, 'Set Number of Columns') menuTry.append(ID::SETVIRTWIDTH, 'Set Virtual Width') menuTry.append_check_item(ID::SETPGDISABLED, 'Disable Grid') menuTry.append_separator menuTry.append(ID::TESTXRC, 'Display XRC sample') menuFile.append(ID::RUNMINIMAL, 'Run Minimal Sample') menuFile.append_separator menuFile.append(ID::RUNTESTFULL, 'Run Tests (full)') menuFile.append(ID::RUNTESTPARTIAL, 'Run Tests (fast)') menuFile.append_separator menuFile.append(ID::QUIT, "E&xit\tAlt-X", 'Quit this program') # Now append the freshly created menu to the menu bar... menuBar = Wx::MenuBar.new menuBar.append(menuFile, '&File') menuBar.append(menuTry, '&Try These!') menuBar.append(menuTools1, '&Basic') menuBar.append(menuTools2, '&Advanced') menuBar.append(menuHelp, '&Help') # ... and attach this menu bar to the frame self.menu_bar = menuBar if Wx.has_feature?(:USE_STATUSBAR) # create a status bar create_status_bar(1) set_status_text('') end # USE_STATUSBAR # this is default with wxRuby # Register all editors (SpinCtrl etc.) # wxPropertyGridInterface::RegisterAdditionalEditors() # Register our sample custom editors @sampleMultiButtonEditor = Wx::PG::PropertyGrid.register_editor_class(WxSampleMultiButtonEditor.new) @panel = Wx::Panel.new(self, Wx::ID_ANY, Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE, Wx::TAB_TRAVERSAL) style = Wx::PG::PG_BOLD_MODIFIED | Wx::PG::PG_SPLITTER_AUTO_CENTER | Wx::PG::PG_AUTO_SORT | #Wx::PG::PG_HIDE_MARGIN|Wx::PG::PG_STATIC_SPLITTER | #Wx::PG::PG_TOOLTIPS | #Wx::PG::PG_HIDE_CATEGORIES | #Wx::PG::PG_LIMITED_EDITING | Wx::PG::PG_TOOLBAR | Wx::PG::PG_DESCRIPTION # extra style xtra_style = Wx::PG::PG_EX_MODE_BUTTONS | Wx::PG::PG_EX_MULTIPLE_SELECTION #| Wx::PG::PG_EX_AUTO_UNSPECIFIED_VALUES #| Wx::PG::PG_EX_GREY_LABEL_WHEN_DISABLED #| Wx::PG::PG_EX_HELP_AS_TOOLTIPS if Wx.has_feature?(:ALWAYS_NATIVE_DOUBLE_BUFFER) xtra_style |= Wx::PG::PG_EX_NATIVE_DOUBLE_BUFFERING end # ALWAYS_NATIVE_DOUBLE_BUFFER create_grid(style, xtra_style) @topSizer = Wx::BoxSizer.new(Wx::VERTICAL) @topSizer.add(@propGridManager, Wx::SizerFlags.new(1).expand) # Button for tab traversal testing btnSizer = Wx::BoxSizer.new(Wx::HORIZONTAL) btnSizer.add(Wx::Button.new(@panel, Wx::ID_ANY, 'Should be able to move here with Tab'), Wx::SizerFlags.new(1).border(Wx::ALL, 10)) btnSizer.add(Wx::Button.new(@panel, ID::SHOWPOPUP, 'Show Popup'), Wx::SizerFlags.new(1).border(Wx::ALL, 10)) @topSizer.add(btnSizer, Wx::SizerFlags.new(0).border(Wx::ALL, 5).expand) @panel.set_sizer(@topSizer) @topSizer.set_size_hints(@panel) @panel.layout if Wx.has_feature?(:USE_LOGWINDOW) # Create log window @logWindow = Wx::LogWindow.new(self, 'Log Messages', false) @logWindow.frame.move(position.x + size.width + 10, position.y) @logWindow.show end evt_idle :on_idle evt_move :on_move evt_size :on_resize # This occurs when a property is selected evt_pg_selected ID::PGID, :on_property_grid_select # This occurs when a property value changes evt_pg_changed ID::PGID, :on_property_grid_change # This occurs just prior a property value is changed evt_pg_changing ID::PGID, :on_property_grid_changing # This occurs when a mouse moves over another property evt_pg_highlighted ID::PGID, :on_property_grid_highlight # This occurs when mouse is right-clicked. evt_pg_right_click ID::PGID, :on_property_grid_item_right_click # This occurs when mouse is double-clicked. evt_pg_double_click ID::PGID, :on_property_grid_item_double_click # This occurs when propgridmanager's page changes. evt_pg_page_changed ID::PGID, :on_property_grid_page_change # This occurs when user starts editing a property label evt_pg_label_edit_begin ID::PGID, :on_property_grid_label_edit_begin # This occurs when user stops editing a property label evt_pg_label_edit_ending ID::PGID, :on_property_grid_label_edit_ending # This occurs when property's editor button (if any) is clicked. evt_button ID::PGID, :on_property_grid_button_click evt_pg_item_collapsed ID::PGID, :on_property_grid_item_collapse evt_pg_item_expanded ID::PGID, :on_property_grid_item_expand evt_pg_col_begin_drag ID::PGID, :on_property_grid_col_begin_drag evt_pg_col_dragging ID::PGID, :on_property_grid_col_dragging evt_pg_col_end_drag ID::PGID, :on_property_grid_col_end_drag evt_text ID::PGID, :on_property_grid_text_update # # Rest of the events are not property grid specific evt_key_down :on_property_grid_key_event evt_key_up :on_property_grid_key_event evt_menu ID::APPENDPROP, :on_append_prop_click evt_menu ID::APPENDCAT, :on_append_cat_click evt_menu ID::INSERTPROP, :on_insert_prop_click evt_menu ID::INSERTCAT, :on_insert_cat_click evt_menu ID::DELETE, :on_del_prop_click evt_menu ID::DELETER, :on_del_prop_r_click evt_menu ID::UNSPECIFY, :on_misc evt_menu ID::DELETEALL, :on_clear_click evt_menu ID::ENABLE, :on_enable_disable evt_menu ID::SETREADONLY, :on_set_read_only evt_menu ID::HIDE, :on_hide evt_menu ID::BOOL_CHECKBOX, :on_bool_checkbox evt_menu ID::ITERATE1, :on_iterate1_click evt_menu ID::ITERATE2, :on_iterate2_click evt_menu ID::ITERATE3, :on_iterate3_click evt_menu ID::ITERATE4, :on_iterate4_click evt_menu ID::ONEXTENDEDKEYNAV, :on_extended_key_nav evt_menu ID::SETBGCOLOUR, :on_set_background_colour evt_menu ID::SETBGCOLOURRECUR, :on_set_background_colour evt_menu ID::CLEARMODIF, :on_clear_modify_status_click evt_menu ID::FREEZE, :on_freeze_click evt_menu ID::ENABLELABELEDITING, :on_enable_label_editing if Wx.has_feature? :USE_HEADERCTRL evt_menu ID::SHOWHEADER, :on_show_header end evt_menu ID::DUMPLIST, :on_dump_list evt_menu ID::COLOURSCHEME1, :on_colour_scheme evt_menu ID::COLOURSCHEME2, :on_colour_scheme evt_menu ID::COLOURSCHEME3, :on_colour_scheme evt_menu ID::COLOURSCHEME4, :on_colour_scheme evt_menu ID::ABOUT, :on_about evt_menu ID::QUIT, :on_close_click evt_menu ID::CATCOLOURS, :on_cat_colours evt_menu ID::SETCOLUMNS, :on_set_columns evt_menu ID::SETVIRTWIDTH, :on_set_virtual_width evt_menu ID::SETPGDISABLED, :on_set_grid_disabled evt_menu ID::TESTXRC, :on_test_xrc evt_menu ID::ENABLECOMMONVALUES, :on_enable_common_values evt_menu ID::SELECTSTYLE, :on_select_style evt_menu ID::STATICLAYOUT, :on_misc evt_menu ID::COLLAPSE, :on_misc evt_menu ID::COLLAPSEALL, :on_misc evt_menu ID::POPULATE1, :on_populate_click evt_menu ID::POPULATE2, :on_populate_click evt_menu ID::GETVALUES, :on_misc evt_menu ID::SETVALUES, :on_misc evt_menu ID::SETVALUES2, :on_misc evt_menu ID::FITCOLUMNS, :on_fit_columns_click evt_menu ID::CHANGEFLAGSITEMS, :on_change_flags_prop_items_click evt_menu ID::RUNTESTFULL, :on_misc evt_menu ID::RUNTESTPARTIAL, :on_misc evt_menu ID::TESTINSERTCHOICE, :on_insert_choice evt_menu ID::TESTDELETECHOICE, :on_delete_choice evt_menu ID::INSERTPAGE, :on_insert_page evt_menu ID::REMOVEPAGE, :on_remove_page evt_menu ID::SAVESTATE, :on_save_state evt_menu ID::RESTORESTATE, :on_restore_state evt_menu ID::SETSPINCTRLEDITOR, :on_set_spin_ctrl_editor_click evt_menu ID::TESTREPLACE, :on_test_replace_click evt_menu ID::SETPROPERTYVALUE, :on_set_property_value evt_menu ID::RUNMINIMAL, :on_run_minimal_click evt_update_ui ID::CATCOLOURS, :on_cat_colours_update_ui evt_context_menu :on_context_menu evt_button ID::SHOWPOPUP, :on_show_popup end # # Normally, wxPropertyGrid does not check whether item with identical # label already exists. However, since in this sample we use labels for # identifying properties, we have to be sure not to generate identical # labels. # def self.generate_unique_property_label(pg, base_label) count = -1; if pg.get_property_by_label(base_label) while true count += 1 new_label = "%s %i" % [base_label,count] break unless pg.get_property_by_label(new_label) end end base_label = new_label if count >= 0 base_label end # utility function to find an icon relative to this ruby script def local_icon_file(icon_name) File.join(File.dirname(__FILE__), icon_name) end def create_grid(style, extraStyle) # # This function (re)creates the property grid in our sample # if style == -1 # default style style = Wx::PG::PG_BOLD_MODIFIED | Wx::PG::PG_SPLITTER_AUTO_CENTER | Wx::PG::PG_AUTO_SORT | #Wx::PG::PG_HIDE_MARGIN|Wx::PG::PG_STATIC_SPLITTER | #Wx::PG::PG_TOOLTIPS | #Wx::PG::PG_HIDE_CATEGORIES | #Wx::PG::PG_LIMITED_EDITING | Wx::PG::PG_TOOLBAR | Wx::PG::PG_DESCRIPTION end if extraStyle == -1 # default extra style extraStyle = Wx::PG::PG_EX_MODE_BUTTONS | Wx::PG::PG_EX_MULTIPLE_SELECTION #| Wx::PG::PG_EX_AUTO_UNSPECIFIED_VALUES #| Wx::PG::PG_EX_GREY_LABEL_WHEN_DISABLED #| Wx::PG::PG_EX_HELP_AS_TOOLTIPS if Wx.has_feature?(:ALWAYS_NATIVE_DOUBLE_BUFFER) extraStyle |= Wx::PG::PG_EX_NATIVE_DOUBLE_BUFFERING end # ALWAYS_NATIVE_DOUBLE_BUFFER end # # This shows how to combine two static choice descriptors @combinedFlags.add(FS_WINDOWSTYLE_LABELS, FS_WINDOWSTYLE_VALUES) @combinedFlags.add(FS_FRAMESTYLE_LABELS, FS_FRAMESTYLE_VALUES) pgman = @propGridManager = Wx::PG::PropertyGridManager.new(@panel, # Don't change this into wxID_ANY in the sample, or the # event handling will obviously be broken. ID::PGID, # wxID_ANY Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE, style) @propGrid = pgman.grid pgman.set_extra_style(extraStyle) # This is the default validation failure behaviour @propGridManager.set_validation_failure_behavior(Wx::PG::PG_VFB_MARK_CELL|Wx::PG::PG_VFB_SHOW_MESSAGEBOX) @propGridManager.grid.set_vertical_spacing(2) # # Set somewhat different unspecified value appearance cell = Wx::PG::PGCell.new cell.text = 'Unspecified' cell.set_fg_col(Wx::LIGHT_GREY) @propGrid.set_unspecified_value_appearance(cell) populate_grid @propGrid.make_column_editable(0, @labelEditingEnabled) @propGridManager.show_header(@hasHeader) @propGridManager.set_column_title(2, 'Units') if @hasHeader end def replace_grid(style, extraStyle) pgmanOld = @propGridManager; create_grid(style, extraStyle) @topSizer.replace(pgmanOld, @propGridManager) pgmanOld.destroy @propGridManager.set_focus @panel.layout end # These are used in CreateGrid(), and in tests to compose # grids for testing purposes. def populate_grid pgman = @propGridManager; pgman.add_page('Standard Items') populate_with_standard_items pgman.add_page('wxWidgets Library Config') populate_with_library_config myPage = WxMyPropertyGridPage.new myPage.append(Wx::PG::IntProperty.new("IntProperty", Wx::PG::PG_LABEL, 12345678)) # Use WxMyPropertyGridPage (see above) to test the # custom wxPropertyGridPage feature. pgman.add_page("Examples", Wx::BitmapBundle.new, myPage) populate_with_examples end def populate_with_standard_items pgman = @propGridManager pg = pgman.get_page("Standard Items") # Append is ideal way to add items to wxPropertyGrid. pg.append(Wx::PG::PropertyCategory.new("Appearance", Wx::PG::PG_LABEL)) pg.append(Wx::PG::StringProperty.new("Label", Wx::PG::PG_LABEL, get_title)) pg.append(Wx::PG::FontProperty.new("Font", Wx::PG::PG_LABEL)) pg.set_property_help_string("Font", "Editing this will change font used in the property grid.") pg.append(Wx::PG::SystemColourProperty.new("Margin Colour",Wx::PG::PG_LABEL, Wx::PG::ColourPropertyValue.new(pg.get_grid.get_margin_colour))) pg.append(Wx::PG::SystemColourProperty.new("Cell Colour",Wx::PG::PG_LABEL, pg.grid.get_cell_background_colour)) pg.append(Wx::PG::SystemColourProperty.new("Cell Text Colour",Wx::PG::PG_LABEL, pg.grid.get_cell_text_colour)) pg.append(Wx::PG::SystemColourProperty.new("Line Colour",Wx::PG::PG_LABEL, pg.grid.get_line_colour)) pg.append(Wx::PG::FlagsProperty.new("Window Styles",Wx::PG::PG_LABEL, @combinedFlags, get_window_style)) pg.append(Wx::PG::CursorProperty.new("Cursor",Wx::PG::PG_LABEL)) pg.append(Wx::PG::PropertyCategory.new("Position","PositionCategory")) pg.set_property_help_string("PositionCategory", "Change in items in this category will cause respective changes in frame.") # Let's demonstrate 'Units' attribute here # Note that we use many attribute constants instead of strings here # (for instance, Wx::PG::PG_ATTR_MIN, instead of "min"). # Using constant may reduce binary size. pg.append(Wx::PG::IntProperty.new("Height",Wx::PG::PG_LABEL,480)) pg.set_property_attribute("Height", Wx::PG::PG_ATTR_MIN, 10) pg.set_property_attribute("Height", Wx::PG::PG_ATTR_MAX, 2048) pg.set_property_attribute("Height", Wx::PG::PG_ATTR_UNITS, "Pixels") # Set value to unspecified so that Hint attribute will be demonstrated pg.set_property_value_unspecified("Height") pg.set_property_attribute("Height", Wx::PG::PG_ATTR_HINT, "Enter new height for window") # Difference between hint and help string is that the hint is shown in # an empty value cell, while help string is shown either in the # description text box, as a tool tip, or on the status bar. pg.set_property_help_string("Height", "This property uses attributes \"Units\" and \"Hint\".") pg.append(Wx::PG::IntProperty.new("Width",Wx::PG::PG_LABEL,640)) pg.set_property_attribute("Width", Wx::PG::PG_ATTR_MIN, 10) pg.set_property_attribute("Width", Wx::PG::PG_ATTR_MAX, 2048) pg.set_property_attribute("Width", Wx::PG::PG_ATTR_UNITS, "Pixels") pg.set_property_value_unspecified("Width") pg.set_property_attribute("Width", Wx::PG::PG_ATTR_HINT, "Enter new width for window") pg.set_property_help_string("Width", "This property uses attributes \"Units\" and \"Hint\".") pg.append(Wx::PG::IntProperty.new("X",Wx::PG::PG_LABEL,10)) pg.set_property_attribute("X", Wx::PG::PG_ATTR_UNITS, "Pixels") pg.set_property_help_string("X", "This property uses \"Units\" attribute.") pg.append Wx::PG::IntProperty.new("Y",Wx::PG::PG_LABEL,10) pg.set_property_attribute("Y", Wx::PG::PG_ATTR_UNITS, "Pixels") pg.set_property_help_string("Y", "This property uses \"Units\" attribute.") disabledHelpString = "This property is simply disabled. In order to have label disabled as well, "+ "you need to set Wx::PG::PG_EX_GREY_LABEL_WHEN_DISABLED using SetExtraStyle." pg.append(Wx::PG::PropertyCategory.new("Environment",Wx::PG::PG_LABEL)) pg.append(Wx::PG::StringProperty.new("Operating System",Wx::PG::PG_LABEL, Wx.get_os_description)) pg.append(Wx::PG::StringProperty.new("User Id",Wx::PG::PG_LABEL, Wx.get_user_id)) pg.append(Wx::PG::DirProperty.new("User Home",Wx::PG::PG_LABEL, Wx.get_user_home)) pg.append(Wx::PG::StringProperty.new("User Name",Wx::PG::PG_LABEL, Wx.get_user_name)) # Disable some of them pg.disable_property("Operating System") pg.disable_property("User Id") pg.disable_property("User Name") pg.set_property_help_string("Operating System", disabledHelpString) pg.set_property_help_string("User Id", disabledHelpString) pg.set_property_help_string("User Name", disabledHelpString) pg.append(Wx::PG::PropertyCategory.new("More Examples",Wx::PG::PG_LABEL)) pg.append(WxFontDataProperty.new("FontDataProperty", Wx::PG::PG_LABEL)) pg.set_property_help_string("FontDataProperty", "This demonstrates Wx::PG::FontDataProperty class defined in this sample app. "+ "It is exactly like Wx::PG::FontProperty from the library, but also has colour sub-property.") pg.append(WxDirsProperty.new("DirsProperty",Wx::PG::PG_LABEL)) pg.set_property_help_string("DirsProperty", "This demonstrates Wx::PG::DirsProperty class defined in this sample app. "+ "It is built with WX_PG_IMPLEMENT_ARRAYSTRING_PROPERTY_WITH_VALIDATOR macro, "+ "with custom action (dir dialog popup) defined.") arrdbl = [ -1.0, -0.5, 0.0, 0.5, 1.0 ] pg.append(WxArrayDoubleProperty.new("ArrayDoubleProperty",Wx::PG::PG_LABEL,arrdbl)) pg.set_property_attribute("ArrayDoubleProperty",Wx::PG::PG_FLOAT_PRECISION,2) pg.set_property_help_string("ArrayDoubleProperty", "This demonstrates Wx::PG::ArrayDoubleProperty class defined in this sample app. "+ "It is an example of a custom list editor property.") pg.append(Wx::PG::LongStringProperty.new("Information",Wx::PG::PG_LABEL, "Editing properties will have immediate effect on this window, "+ "and vice versa (at least in most cases, that is).")) pg.set_property_help_string("Information", "This property is read-only.") pg.set_property_read_only("Information", true) # # Set test information for cells in columns 3 and 4 # (reserve column 2 for displaying units) bmp = Wx::ArtProvider.get_bitmap(Wx::ART_FOLDER) pg.grid.each_property do |p| continue if p.category? pg.set_property_cell(p, 3, "Cell 3", bmp) pg.set_property_cell(p, 4, "Cell 4", Wx::BitmapBundle.new, Wx::WHITE, Wx::BLACK) end end def populate_with_examples pgman = @propGridManager pg = pgman.get_page("Examples") if Wx.has_feature?(:USE_SPINBTN) pg.append(Wx::PG::IntProperty.new("SpinCtrl", Wx::PG::PG_LABEL, 0)) pg.set_property_editor("SpinCtrl", Wx::PG::PG_EDITOR_SPIN_CTRL) pg.set_property_attribute("SpinCtrl", Wx::PG::PG_ATTR_MIN, -2) # Use constants instead of string pg.set_property_attribute("SpinCtrl", Wx::PG::PG_ATTR_MAX, 16384) # for reduced binary size. pg.set_property_attribute("SpinCtrl", Wx::PG::PG_ATTR_SPINCTRL_STEP, 2) pg.set_property_attribute("SpinCtrl", Wx::PG::PG_ATTR_SPINCTRL_MOTION, true) pg.set_property_attribute("SpinCtrl", Wx::PG::PG_ATTR_SPINCTRL_WRAP, true) pg.set_property_help_string("SpinCtrl", "This is regular Wx::PG::IntProperty, which editor has been "+ "changed to Wx::PG::PGEditor_SpinCtrl. Note however that "+ "static wxPropertyGrid::RegisterAdditionalEditors() "+ "needs to be called prior to using it.") end # Add bool property pg.append(Wx::PG::BoolProperty.new("BoolProperty", Wx::PG::PG_LABEL, false)) # Add bool property with check box pg.append(Wx::PG::BoolProperty.new("BoolProperty with CheckBox", Wx::PG::PG_LABEL, false)) pg.set_property_attribute("BoolProperty with CheckBox", Wx::PG::PG_BOOL_USE_CHECKBOX, true) pg.set_property_help_string("BoolProperty with CheckBox", "Property attribute Wx::PG::PG_BOOL_USE_CHECKBOX has been set to true.") prop = pg.append(Wx::PG::FloatProperty.new("FloatProperty", Wx::PG::PG_LABEL, 1234500.23)) prop.set_attribute(Wx::PG::PG_ATTR_MIN, -100.12) # A string property that can be edited in a separate editor dialog. pg.append(Wx::PG::LongStringProperty.new("LongStringProperty", "LongStringProp", "This is much longer string than the first one. Edit it by clicking the button.")) # A property that edits a wxArrayString. example_array = [ "String 1", "String 2", "String 3" ] pg.append(Wx::PG::ArrayStringProperty.new("ArrayStringProperty", Wx::PG::PG_LABEL, example_array)) # A file selector property. Note that argument between name # and initial value is wildcard (format same as in wxFileDialog). prop = Wx::PG::FileProperty.new("FileProperty", "TextFile") pg.append(prop) prop.set_attribute(Wx::PG::PG_FILE_WILDCARD,"Text Files (*.txt)|*.txt") prop.set_attribute(Wx::PG::PG_DIALOG_TITLE,"Custom File Dialog Title") prop.set_attribute(Wx::PG::PG_FILE_SHOW_FULL_PATH,false) if Wx::PLATFORM == 'WXMSW' prop.set_attribute(Wx::PG::PG_FILE_SHOW_RELATIVE_PATH,"C:\\Windows") pg.set_property_value(prop,"C:\\Windows\\System32\\msvcrt71.dll") end if Wx.has_feature? :USE_IMAGE # An image file property. Arguments are just like for FileProperty, but # wildcard is missing (it is autogenerated from supported image formats). # If you really need to override it, create property separately, and call # its SetWildcard method. pg.append(Wx::PG::ImageFileProperty.new("ImageFile", Wx::PG::PG_LABEL)) end pid = pg.append(Wx::PG::ColourProperty.new("ColourProperty",Wx::PG::PG_LABEL,Wx::RED)) pg.set_property_editor("ColourProperty", Wx::PG::PG_EDITOR_COMBO_BOX) pg.get_property("ColourProperty").set_auto_unspecified(true) pg.set_property_help_string("ColourProperty", "wxPropertyGrid::SetPropertyEditor method has been used to change "+ "editor of this property to Wx::PG::PGEditor_ComboBox)") pid = pg.append(Wx::PG::ColourProperty.new("ColourPropertyWithAlpha", Wx::PG::PG_LABEL, Wx::Colour.new(15, 200, 95, 128))) pg.set_property_attribute("ColourPropertyWithAlpha", Wx::PG::PG_COLOUR_HAS_ALPHA, true) pg.set_property_help_string("ColourPropertyWithAlpha", "Attribute \"HasAlpha\" is set to true for this property.") # # This demonstrates using alternative editor for colour property # to trigger colour dialog directly from button. pg.append(Wx::PG::ColourProperty.new("ColourProperty2",Wx::PG::PG_LABEL,Wx::GREEN)) # # Wx::PG::EnumProperty does not store strings or even list of strings # (so that's why they are static in function). enum_prop_labels = [ "One Item", "Another Item", "One More", "This Is Last" ] # this value array would be optional if values matched string indexes enum_prop_values = [ 40, 80, 120, 160 ] # note that the initial value (the last argument) is the actual value, # not index or anything like that. Thus, our value selects "Another Item". pg.append(Wx::PG::EnumProperty.new("EnumProperty",Wx::PG::PG_LABEL, enum_prop_labels, enum_prop_values, 80)) soc = Wx::PG::PGChoices.new # use basic table from our previous example # can also set/add wxArrayStrings and wxArrayInts directly. soc.set(enum_prop_labels, enum_prop_values) # add extra items soc.add("Look, it continues", 200) soc.add("Even More", 240) soc.add("And More", 280) soc.add('', 300) soc.add("True End of the List", 320) # Test custom colours ([] operator of Wx::PG::PGChoices returns # references to Wx::PG::PGChoiceEntry). soc[1].set_fg_col(Wx::RED) soc[1].set_bg_col(Wx::LIGHT_GREY) soc[2].set_fg_col(Wx::GREEN) soc[2].set_bg_col(Wx::LIGHT_GREY) soc[3].set_fg_col(Wx::BLUE) soc[3].set_bg_col(Wx::LIGHT_GREY) soc[4].set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FOLDER)) pg.append(Wx::PG::EnumProperty.new("EnumProperty 2", Wx::PG::PG_LABEL, soc, 240)) pg.get_property("EnumProperty 2").add_choice("Testing Extra", 360) # Here we only display the original 'soc' choices pg.append(Wx::PG::EnumProperty.new("EnumProperty 3",Wx::PG::PG_LABEL, soc, 240)) # Test Hint attribute in EnumProperty pg.get_property("EnumProperty 3").set_attribute(Wx::PG::PG_ATTR_HINT, "Dummy Hint") pg.set_property_help_string("EnumProperty 3", "This property uses \"Hint\" attribute.") # 'soc' plus one exclusive extra choice "4th only" pg.append(Wx::PG::EnumProperty.new("EnumProperty 4",Wx::PG::PG_LABEL, soc, 240)) pg.get_property("EnumProperty 4").add_choice("4th only", 360) pg.set_property_help_string("EnumProperty 4", "Should have one extra item when compared to EnumProperty 3") # Plus property value bitmap pg.append(Wx::PG::EnumProperty.new("EnumProperty With Bitmap", "EnumProperty 5", soc, 280)) pg.set_property_help_string("EnumProperty 5", "Should have bitmap in front of the displayed value") bmpVal = Wx::ArtProvider.get_bitmap(Wx::ART_REMOVABLE) pg.set_property_image("EnumProperty 5", bmpVal) # Password property example. pg.append(Wx::PG::StringProperty.new("Password",Wx::PG::PG_LABEL, "password")) pg.set_property_attribute("Password", Wx::PG::PG_STRING_PASSWORD, true) pg.set_property_help_string("Password", "Has attribute Wx::PG::PG_STRING_PASSWORD set to true") # String editor with dir selector button. Uses wxEmptyString as name, which # is allowed (naturally, in this case property cannot be accessed by name). pg.append(Wx::PG::DirProperty.new("DirProperty", Wx::PG::PG_LABEL, Wx.get_user_home)) pg.set_property_attribute("DirProperty", Wx::PG::PG_DIALOG_TITLE, "This is a custom dir dialog title") # Add string property - first arg is label, second name, and third initial value pg.append(Wx::PG::StringProperty.new("StringProperty", Wx::PG::PG_LABEL)) pg.set_property_max_length("StringProperty", 6) pg.set_property_help_string("StringProperty", "Max length of this text has been limited to 6, using wxPropertyGrid::SetPropertyMaxLength.") # Set value after limiting so that it will be applied pg.set_property_value("StringProperty", "some text") # # Demonstrate "AutoComplete" attribute pg.append(Wx::PG::StringProperty.new("StringProperty AutoComplete", Wx::PG::PG_LABEL)) autoCompleteStrings = [ "One choice", "Another choice", "Another choice, yeah", "Yet another choice", "Yet another choice, bear with me" ] pg.set_property_attribute("StringProperty AutoComplete", Wx::PG::PG_ATTR_AUTOCOMPLETE, autoCompleteStrings) pg.set_property_help_string("StringProperty AutoComplete", "AutoComplete attribute has been set for this property "+ "(try writing something beginning with 'a', 'o' or 'y').") # Add string property with arbitrarily wide bitmap in front of it. We # intentionally lower-than-typical row height here so that the ugly # scaling code won't be run. pg.append(Wx::PG::StringProperty.new("StringPropertyWithBitmap", Wx::PG::PG_LABEL, "Test Text")) myTestBitmap1x = Wx::Bitmap.new(60, 15, 32) Wx::MemoryDC.draw_on(myTestBitmap1x) do |mdc| mdc.set_background(Wx::WHITE_BRUSH) mdc.clear mdc.set_pen(Wx::BLACK_PEN) mdc.set_brush(Wx::WHITE_BRUSH) mdc.draw_rectangle(0, 0, 60, 15) mdc.draw_line(0, 0, 59, 14) mdc.set_text_foreground(Wx::BLACK) mdc.draw_text("x1", 0, 0) end myTestBitmap2x = Wx::Bitmap.new(120, 30, 32) Wx::MemoryDC.draw_on(myTestBitmap2x) do |mdc| mdc.set_background(Wx::WHITE_BRUSH) mdc.clear mdc.set_pen(Wx::Pen.new(Wx::BLUE, 2)) mdc.set_brush(Wx::WHITE_BRUSH) mdc.draw_rectangle(0, 0, 120, 30) mdc.draw_line(0, 0, 119, 31) mdc.set_text_foreground(Wx::BLUE) f = mdc.font f.set_pixel_size(f.get_pixel_size * 2) mdc.set_font(f) mdc.draw_text("x2", 0, 0) end myTestBitmap2x.set_scale_factor(2) pg.set_property_image("StringPropertyWithBitmap", Wx::BitmapBundle.from_bitmaps(myTestBitmap1x, myTestBitmap2x)) # Multi choice dialog. tchoices = %w[Cabbage Carrot Onion Potato Strawberry] tchoicesValues = %w[Carrot Potato] pg.append(Wx::PG::EnumProperty.new("EnumProperty X",Wx::PG::PG_LABEL, tchoices)) pg.append(Wx::PG::MultiChoiceProperty.new("MultiChoiceProperty", Wx::PG::PG_LABEL, tchoices, tchoicesValues)) pg.set_property_attribute("MultiChoiceProperty", Wx::PG::PG_ATTR_MULTICHOICE_USERSTRINGMODE, 1) pg.append(WxSizeProperty.new("SizeProperty", "Size", get_size)) pg.append(WxPointProperty.new("PointProperty", "Position", get_position)) # UInt samples pg.append(Wx::PG::UIntProperty.new("UIntProperty", Wx::PG::PG_LABEL, 0xFEEEFEEEFEEE)) pg.set_property_attribute("UIntProperty", Wx::PG::PG_UINT_PREFIX, Wx::PG::PG_PREFIX_NONE) pg.set_property_attribute("UIntProperty", Wx::PG::PG_UINT_BASE, Wx::PG::PG_BASE_HEX) #pg.set_property_attribute("UIntProperty", Wx::PG::PG_UINT_PREFIX, Wx::PG::PG_PREFIX_NONE) #pg.set_property_attribute("UIntProperty", Wx::PG::PG_UINT_BASE, Wx::PG::PG_BASE_OCT) # # Wx::PG::EditEnumProperty eech = Wx::PG::PGChoices.new([ "Choice 1", "Choice 2", "Choice 3" ]) pg.append(Wx::PG::EditEnumProperty.new("EditEnumProperty", Wx::PG::PG_LABEL, eech, "Choice not in the list")) # Test Hint attribute in EditEnumProperty pg.get_property("EditEnumProperty").set_attribute(Wx::PG::PG_ATTR_HINT, "Dummy Hint") #wxString v_; #wxTextValidator validator1(wxFILTER_NUMERIC,&v_) #pg.SetPropertyValidator("EditEnumProperty", validator1) if Wx.has_feature? :USE_DATETIME # # Wx::PG::DateTimeProperty pg.append(Wx::PG::DateProperty.new("DateProperty", Wx::PG::PG_LABEL, Time.now)) if Wx.has_feature? :USE_DATEPICKCTRL pg.set_property_attribute("DateProperty", Wx::PG::PG_DATE_PICKER_STYLE, Wx::DP_DROPDOWN|Wx::DP_SHOWCENTURY|Wx::DP_ALLOWNONE) pg.set_property_help_string("DateProperty", "Attribute Wx::PG::PG_DATE_PICKER_STYLE has been set to (long)"+ "(wxDP_DROPDOWN | wxDP_SHOWCENTURY | wxDP_ALLOWNONE).") end end # # Add Triangle properties as both Wx::PG::TriangleProperty and # a generic parent property (using Wx::PG::StringProperty). # topId = pg.append(Wx::PG::StringProperty.new("3D Object", Wx::PG::PG_LABEL, "")) pid = pg.append_in(topId, Wx::PG::StringProperty.new("Triangle 1", "Triangle 1", "")) pg.append_in(pid, WxVectorProperty.new("A", Wx::PG::PG_LABEL)) pg.append_in(pid, WxVectorProperty.new("B", Wx::PG::PG_LABEL)) pg.append_in(pid, WxVectorProperty.new("C", Wx::PG::PG_LABEL)) pg.append_in(topId, WxTriangleProperty.new("Triangle 2", "Triangle 2")) pg.set_property_help_string("3D Object", "3D Object is Wx::PG::StringProperty with value \"\". Two of its children are similar wxStringProperties with "+ "three Wx::PG::VectorProperty children, and other two are custom wxTriangleProperties.") pid = pg.append_in(topId, Wx::PG::StringProperty.new("Triangle 3", "Triangle 3", "")) pg.append_in(pid, WxVectorProperty.new("A", Wx::PG::PG_LABEL)) pg.append_in(pid, WxVectorProperty.new("B", Wx::PG::PG_LABEL)) pg.append_in(pid, WxVectorProperty.new("C", Wx::PG::PG_LABEL)) pg.append_in(topId, WxTriangleProperty.new("Triangle 4", "Triangle 4")) # # This snippet is a doc sample test # carProp = pg.append(Wx::PG::StringProperty.new("Car", Wx::PG::PG_LABEL, "")) pg.append_in(carProp, Wx::PG::StringProperty.new("Model", Wx::PG::PG_LABEL, "Lamborghini Diablo SV")) pg.append_in(carProp, Wx::PG::IntProperty.new("Engine Size (cc)", Wx::PG::PG_LABEL, 5707)) speedsProp = pg.append_in(carProp, Wx::PG::StringProperty.new("Speeds", Wx::PG::PG_LABEL, "")) pg.append_in(speedsProp, Wx::PG::IntProperty.new("Max. Speed (mph)", Wx::PG::PG_LABEL,290)) pg.append_in(speedsProp, Wx::PG::FloatProperty.new("0-100 mph (sec)", Wx::PG::PG_LABEL,3.9)) pg.append_in(speedsProp, Wx::PG::FloatProperty.new("1/4 mile (sec)", Wx::PG::PG_LABEL,8.6)) # This is how child property can be referred to by name pg.set_property_value("Car.Speeds.Max. Speed (mph)", 300) pg.append_in(carProp, Wx::PG::IntProperty.new("Price ($)", Wx::PG::PG_LABEL, 300000)) pg.append_in(carProp, Wx::PG::BoolProperty.new("Convertible", Wx::PG::PG_LABEL, false)) # Displayed value of "Car" property is now very close to this: # "Lamborghini Diablo SV; 5707 [300; 3.9; 8.6] 300000" # # Test wxSampleMultiButtonEditor pg.append(Wx::PG::LongStringProperty.new("MultipleButtons", Wx::PG::PG_LABEL)) pg.set_property_editor("MultipleButtons", @sampleMultiButtonEditor) # Test SingleChoiceProperty pg.append(WxSingleChoiceProperty.new("SingleChoiceProperty")) # # Test adding variable height bitmaps in Wx::PG::PGChoices bc = Wx::PG::PGChoices.new bc.add("Wee", Wx::ArtProvider.get_bitmap(Wx::ART_CDROM, Wx::ART_OTHER, [16, 16])) bc.add("Not so wee", Wx::ArtProvider.get_bitmap(Wx::ART_FLOPPY, Wx::ART_OTHER, [32, 32])) bc.add("Friggin' huge", Wx::ArtProvider.get_bitmap(Wx::ART_HARDDISK, Wx::ART_OTHER, [64, 64])) pg.append(Wx::PG::EnumProperty.new("Variable Height Bitmaps", Wx::PG::PG_LABEL, bc, 0)) # # Test how non-editable composite strings appear pid = Wx::PG::StringProperty.new("wxRuby Traits", Wx::PG::PG_LABEL, "") pg.set_property_read_only(pid) # # For testing purposes, combine two methods of adding children # pid.append_child(Wx::PG::StringProperty.new("Latest Release", Wx::PG::PG_LABEL, "3.0.0")) pid.append_child(Wx::PG::BoolProperty.new("Win API", Wx::PG::PG_LABEL, true)) pg.append(pid) pg.append_in(pid, Wx::PG::BoolProperty.new("QT", Wx::PG::PG_LABEL, true)) pg.append_in(pid, Wx::PG::BoolProperty.new("Cocoa", Wx::PG::PG_LABEL, true)) pg.append_in(pid, Wx::PG::BoolProperty.new("Haiku", Wx::PG::PG_LABEL, false)) pg.append_in(pid, Wx::PG::StringProperty.new("Trunk Version", Wx::PG::PG_LABEL, Wx::WXRUBY_VERSION)) pg.append_in(pid, Wx::PG::BoolProperty.new("GTK+", Wx::PG::PG_LABEL, true)) pg.append_in(pid, Wx::PG::BoolProperty.new("Android", Wx::PG::PG_LABEL, false)) add_test_properties(pg) end def populate_with_library_config pgman = @propGridManager; pg = pgman.get_page("wxWidgets Library Config") # Set custom column proportions (here in the sample app we need # to check if the grid has wxPG_SPLITTER_AUTO_CENTER style. You usually # need not to do it in your application). if pgman.has_flag(Wx::PG::PG_SPLITTER_AUTO_CENTER) pg.set_column_proportion(0, 3) pg.set_column_proportion(1, 1) end bmp = Wx::ArtProvider.get_bitmap(Wx::ART_REPORT_VIEW) italicFont = pgman.grid.get_caption_font italicFont.set_style(Wx::FONTSTYLE_ITALIC) italicFontHelp = "Font of this property's wxPGCell has " + "been modified. Obtain property's cell " + "with wxPGProperty::" + "GetOrCreateCell(column)." pid = pg.append(Wx::PG::PropertyCategory.new("wxWidgets Library Configuration" )) pg.set_property_cell(pid, 0, Wx::PG::PG_LABEL, bmp) # Both of following lines would set a label for the second column pg.set_property_cell(pid, 1, "Is Enabled") pid.set_value("Is Enabled") _ADD_WX_LIB_CONF_GROUP = ->(label) { cat = pg.append_in(pid, Wx::PG::PropertyCategory.new(label)) pg.set_property_cell(cat, 0, Wx::PG::PG_LABEL, bmp) cat.get_cell(0).set_font(italicFont) cat.set_help_string(italicFontHelp) } _ADD_WX_LIB_CONF = ->(sym) { pg.append(Wx::PG::BoolProperty.new(sym.to_s, Wx::PG::PG_LABEL, Wx.has_feature?(sym))) } _ADD_WX_LIB_CONF_NODEF = ->(sym) { pg.append(Wx::PG::BoolProperty.new(sym.to_s, Wx::PG::PG_LABEL, Wx.has_feature?(sym))) pg.disable_property(sym.to_s) unless Wx.has_feature?(sym) } _ADD_WX_LIB_CONF_GROUP.call("Global Settings") _ADD_WX_LIB_CONF.call(:USE_GUI) _ADD_WX_LIB_CONF_GROUP.call("Compatibility Settings") if Wx.has_feature?(:WXWIN_COMPATIBILITY_3_0) _ADD_WX_LIB_CONF.call(:WXWIN_COMPATIBILITY_3_0) end _ADD_WX_LIB_CONF_NODEF.call(:FONT_SIZE_COMPATIBILITY) _ADD_WX_LIB_CONF_NODEF.call(:DIALOG_UNIT_COMPATIBILITY) _ADD_WX_LIB_CONF_GROUP.call("Debugging Settings") _ADD_WX_LIB_CONF.call(:USE_DEBUG_CONTEXT) _ADD_WX_LIB_CONF.call(:USE_MEMORY_TRACING) _ADD_WX_LIB_CONF.call(:USE_GLOBAL_MEMORY_OPERATORS) _ADD_WX_LIB_CONF.call(:USE_DEBUG_NEW_ALWAYS) _ADD_WX_LIB_CONF.call(:USE_ON_FATAL_EXCEPTION) _ADD_WX_LIB_CONF_GROUP.call("Unicode Support") # From wxWidgets 3.3.0 Unicode is the fixed default and the setup macro 'wxUSE_UNICODE' removed if Wx::WXWIDGETS_VERSION < '3.3.0' _ADD_WX_LIB_CONF.call(:USE_UNICODE) end _ADD_WX_LIB_CONF.call(:USE_UNICODE_UTF8) _ADD_WX_LIB_CONF_GROUP.call("Global Features") _ADD_WX_LIB_CONF.call(:USE_EXCEPTIONS) _ADD_WX_LIB_CONF.call(:USE_EXTENDED_RTTI) _ADD_WX_LIB_CONF.call(:USE_STL) _ADD_WX_LIB_CONF.call(:USE_LOG) _ADD_WX_LIB_CONF.call(:USE_LOGWINDOW) _ADD_WX_LIB_CONF.call(:USE_LOGGUI) _ADD_WX_LIB_CONF.call(:USE_LOG_DIALOG) _ADD_WX_LIB_CONF.call(:USE_CMDLINE_PARSER) _ADD_WX_LIB_CONF.call(:USE_THREADS) _ADD_WX_LIB_CONF.call(:USE_STREAMS) _ADD_WX_LIB_CONF.call(:USE_STD_IOSTREAM) _ADD_WX_LIB_CONF_GROUP.call("Non-GUI Features") _ADD_WX_LIB_CONF.call(:USE_LONGLONG) _ADD_WX_LIB_CONF.call(:USE_FILE) _ADD_WX_LIB_CONF.call(:USE_FFILE) _ADD_WX_LIB_CONF.call(:USE_FSVOLUME) _ADD_WX_LIB_CONF.call(:USE_TEXTBUFFER) _ADD_WX_LIB_CONF.call(:USE_TEXTFILE) _ADD_WX_LIB_CONF.call(:USE_INTL) _ADD_WX_LIB_CONF.call(:USE_DATETIME) _ADD_WX_LIB_CONF.call(:USE_TIMER) _ADD_WX_LIB_CONF.call(:USE_STOPWATCH) _ADD_WX_LIB_CONF.call(:USE_CONFIG) _ADD_WX_LIB_CONF_NODEF.call(:USE_CONFIG_NATIVE) _ADD_WX_LIB_CONF.call(:USE_DIALUP_MANAGER) _ADD_WX_LIB_CONF.call(:USE_DYNLIB_CLASS) _ADD_WX_LIB_CONF.call(:USE_DYNAMIC_LOADER) _ADD_WX_LIB_CONF.call(:USE_SOCKETS) _ADD_WX_LIB_CONF.call(:USE_FILESYSTEM) _ADD_WX_LIB_CONF.call(:USE_FS_ZIP) _ADD_WX_LIB_CONF.call(:USE_FS_INET) _ADD_WX_LIB_CONF.call(:USE_ZIPSTREAM) _ADD_WX_LIB_CONF.call(:USE_ZLIB) _ADD_WX_LIB_CONF.call(:USE_APPLE_IEEE) _ADD_WX_LIB_CONF.call(:USE_JOYSTICK) _ADD_WX_LIB_CONF.call(:USE_FONTMAP) _ADD_WX_LIB_CONF.call(:USE_MIMETYPE) _ADD_WX_LIB_CONF.call(:USE_PROTOCOL) _ADD_WX_LIB_CONF.call(:USE_PROTOCOL_FILE) _ADD_WX_LIB_CONF.call(:USE_PROTOCOL_FTP) _ADD_WX_LIB_CONF.call(:USE_PROTOCOL_HTTP) _ADD_WX_LIB_CONF.call(:USE_URL) _ADD_WX_LIB_CONF_NODEF.call(:USE_URL_NATIVE) _ADD_WX_LIB_CONF.call(:USE_REGEX) _ADD_WX_LIB_CONF.call(:USE_SYSTEM_OPTIONS) _ADD_WX_LIB_CONF.call(:USE_SOUND) _ADD_WX_LIB_CONF_NODEF.call(:USE_XRC) _ADD_WX_LIB_CONF.call(:USE_XML) # Set them to use check box. pg.set_property_attribute(pid, Wx::PG::PG_BOOL_USE_CHECKBOX, true, Wx::PG::PG_RECURSE) end def on_close_click(event) close(false) end def on_colour_scheme(event) id = event.id if id == ID::COLOURSCHEME1 @propGridManager.grid.reset_colours elsif id == ID::COLOURSCHEME2 # white my_grey_1 = Wx::Colour.new(212,208,200) my_grey_3 = Wx::Colour.new(113,111,100) @propGridManager.freeze @propGridManager.grid.set_margin_colour(Wx::WHITE) @propGridManager.grid.set_caption_background_colour(Wx::WHITE) @propGridManager.grid.set_cell_background_colour(Wx::WHITE) @propGridManager.grid.set_cell_text_colour(my_grey_3) @propGridManager.grid.set_line_colour(my_grey_1) @propGridManager.thaw elsif id == ID::COLOURSCHEME3 # .NET my_grey_1 = Wx::Colour.new(212,208,200) my_grey_2 = Wx::Colour.new(236,233,216) @propGridManager.freeze @propGridManager.grid.set_margin_colour(my_grey_1) @propGridManager.grid.set_caption_background_colour(my_grey_1) @propGridManager.grid.set_line_colour(my_grey_1) @propGridManager.thaw elsif id == ID::COLOURSCHEME4 # cream my_grey_1 = Wx::Colour.new(212,208,200) my_grey_2 = Wx::Colour.new(241,239,226) my_grey_3 = Wx::Colour.new(113,111,100) @propGridManager.freeze @propGridManager.grid.set_margin_colour(Wx::WHITE) @propGridManager.grid.set_caption_background_colour(Wx::WHITE) @propGridManager.grid.set_cell_background_colour(my_grey_2) @propGridManager.grid.set_cell_background_colour(my_grey_2) @propGridManager.grid.set_cell_text_colour(my_grey_3) @propGridManager.grid.set_line_colour(my_grey_1) @propGridManager.thaw end end def on_insert_prop_click(event) if @propGridManager.grid.root.get_child_count == 0 Wx.message_box("No items to relate - first add some with Append.") return end id = @propGridManager.grid.get_selection unless id Wx.message_box("First select a property - new one will be inserted right before that.") return end propLabel = FormMain.generate_unique_property_label(@propGridManager, 'Property') @propGridManager.insert(@propGridManager.get_property_parent(id), id.get_index_in_parent, Wx::PG::StringProperty.new(propLabel)) end def on_append_prop_click(event) propLabel = FormMain.generate_unique_property_label(@propGridManager, 'Property') @propGridManager.append(Wx::PG::StringProperty.new(propLabel)) @propGridManager.refresh end def on_clear_click(event) @propGridManager.grid.clear end def on_append_cat_click(event) propLabel = FormMain.generate_unique_property_label(@propGridManager, 'Category') @propGridManager.append(Wx::PG::PropertyCategory.new(propLabel)) @propGridManager.refresh end def on_insert_cat_click(event) if @propGridManager.grid.root.get_child_count == 0 Wx.message_box("No items to relate - first add some with Append.") return end id = @propGridManager.grid.get_selection unless id Wx.message_box("First select a property - new one will be inserted right before that.") return end propLabel = FormMain.generate_unique_property_label(@propGridManager, 'Category') @propGridManager.insert(@propGridManager.get_property_parent(id), id.get_index_in_parent, Wx::PG::PropertyCategory.new(propLabel)) end def on_del_prop_click(event) id = @propGridManager.grid.get_selection unless id Wx.message_box("First select a property.") return end @propGridManager.delete_property(id) end def on_del_prop_r_click(event) # Delete random property p = @propGridManager.grid.root while true break if p.get_child_count == 0 n = rand(p.get_child_count) p = p.item(n) if !p.category? label = p.get_label @propGridManager.delete_property(p) Wx.log_message("Property deleted: %s", label) break end end end def on_context_menu(event) Wx.log_debug("FormMain::OnContextMenu(%i,%i)", event.get_position.x,event.get_position.y) end def on_enable_disable(event) id = @propGridManager.grid.get_selection unless id Wx.message_box("First select a property.") return end if @propGridManager.is_property_enabled(id) @propGridManager.disable_property(id) @itemEnable.set_item_label("Enable") else @propGridManager.enable_property(id) @itemEnable.set_item_label("Disable") end end def on_set_read_only(event) id = @propGridManager.grid.get_selection unless id Wx.message_box("First select a property.") return end @propGridManager.set_property_read_only(id) end def on_hide(event) id = @propGridManager.grid.get_selection unless id Wx.message_box("First select a property.") return end @propGridManager.hide_property(id, true) end def on_bool_checkbox(evt) @propGridManager.set_property_attribute_all(Wx::PG::PG_BOOL_USE_CHECKBOX, evt.checked?) end def on_set_background_colour(event) pg = @propGridManager.grid prop = pg.get_selection unless prop Wx.message_box("First select a property.") return end col = Wx.get_colour_from_user(self, Wx::WHITE, "Choose colour") if col.ok? flags = (event.id==ID::SETBGCOLOURRECUR) ? Wx::PG::PG_RECURSE : 0 pg.set_property_background_colour(prop, col, flags) end end def on_clear_modify_status_click(event) @propGridManager.clear_modified_status @propGridManager.refresh end def on_freeze_click(event) return unless @propGridManager if event.checked? unless @propGridManager.is_frozen @propGridManager.freeze end else if @propGridManager.frozen? @propGridManager.thaw @propGridManager.refresh end end end def on_enable_label_editing(event) @labelEditingEnabled = event.checked? @propGrid.make_column_editable(0, @labelEditingEnabled) end if Wx.has_feature?(:USE_HEADERCTRL) def on_show_header(event) @hasHeader = event.checked? @propGridManager.show_header(@hasHeader) if @hasHeader @propGridManager.set_column_title(2, "Units") end end end def on_dump_list(event) values = @propGridManager.get_property_values("list", nil, Wx::PG::PG_INC_ATTRIBUTES) text = "This only tests that wxVariant related routines do not crash.\n" Wx.Dialog(self, Wx::ID_ANY,"wxVariant Test", Wx::DEFAULT_POSITION,Wx::DEFAULT_SIZE,Wx::DEFAULT_DIALOG_STYLE|Wx::RESIZE_BORDER) do |dlg| values.get_count.times do |i| v = values[i] strValue = v.to_s if v.name.end_with?("@attr") text << "Attributes:\n" v.count.times do |n| a = v[n] t = " attribute %i: name=\"%s\" (type=\"%s\" value=\"%s\")\n" % [n , a.name, a.type, a.to_s] text << t end else t = "%i: name=\"%s\" type=\"%s\" value=\"%s\"\n" % [i, v.name, v.type, strValue] text << t end end # multi-line text editor dialog spacing = 8; topsizer = Wx::BoxSizer.new(Wx::VERTICAL) rowsizer = Wx::BoxSizer.new(Wx::HORIZONTAL) ed = Wx::TextCtrl.new(dlg, Wx::ID_ANY, text, style: Wx::TE_MULTILINE|Wx::TE_READONLY) rowsizer.add(ed, Wx::SizerFlags.new(1).expand.border(Wx::ALL, spacing)) topsizer.add(rowsizer, Wx::SizerFlags.new(1).expand) rowsizer = Wx::BoxSizer.new(Wx::HORIZONTAL) rowsizer.add(Wx::Button.new(dlg, Wx::ID_OK, "Ok"), Wx::SizerFlags.new.centre_horizontal.centre_vertical.border(Wx::Direction::BOTTOM|Wx::LEFT|Wx::RIGHT, spacing)) topsizer.add(rowsizer, Wx::SizerFlags.new.right) dlg.set_sizer(topsizer) topsizer.set_size_hints(dlg) dlg.set_size([400,300]) dlg.centre dlg.show_modal end end def on_cat_colours_update_ui(event) # Prevent menu item from being checked # if it is selected from improper page. pg = @propGridManager.grid @itemCatColours.enable( !!(pg.get_property_by_name("Appearance") && pg.get_property_by_name("PositionCategory") && pg.get_property_by_name("Environment") && pg.get_property_by_name("More Examples")) ) end def on_cat_colours(event) pg = @propGridManager.grid unless !!(pg.get_property_by_name("Appearance") && pg.get_property_by_name("PositionCategory") && pg.get_property_by_name("Environment") && pg.get_property_by_name("More Examples")) Wx.message_box("First switch to 'Standard Items' page!") return end @propGridManager.freeze if event.checked? # Set custom colours. pg.set_property_text_colour("Appearance", Wx::Colour.new(255,0,0), Wx::PG::PG_DONT_RECURSE) pg.set_property_background_colour("Appearance", Wx::Colour.new(255,255,183)) pg.set_property_text_colour("Appearance", Wx::Colour.new(255,0,183)) pg.set_property_text_colour("PositionCategory", Wx::Colour.new(0,255,0), Wx::PG::PG_DONT_RECURSE) pg.set_property_background_colour("PositionCategory", Wx::Colour.new(255,226,190)) pg.set_property_text_colour("PositionCategory", Wx::Colour.new(255,0,190)) pg.set_property_text_colour("Environment", Wx::Colour.new(0,0,255), Wx::PG::PG_DONT_RECURSE) pg.set_property_background_colour("Environment", Wx::Colour.new(208,240,175)) pg.set_property_text_colour("Environment", Wx::Colour.new(255,255,255)) pg.set_property_background_colour("More Examples", Wx::Colour.new(172,237,255)) pg.set_property_text_colour("More Examples", Wx::Colour.new(172,0,255)) else # Revert to original. pg.set_property_colours_to_default("Appearance") pg.set_property_colours_to_default("Appearance", Wx::PG::PG_RECURSE) pg.set_property_colours_to_default("PositionCategory") pg.set_property_colours_to_default("PositionCategory", Wx::PG::PG_RECURSE) pg.set_property_colours_to_default("Environment") pg.set_property_colours_to_default("Environment", Wx::PG::PG_RECURSE) pg.set_property_colours_to_default("More Examples", Wx::PG::PG_RECURSE) end @propGridManager.thaw @propGridManager.refresh end def on_set_columns(event) colCount = Wx::get_number_from_user("Enter number of columns (2-20).","Columns:", "Change Columns", @propGridManager.get_column_count, 2,20) if colCount != @propGridManager.column_count @propGridManager.set_column_count(colCount) end end def on_set_virtual_width(evt) oldWidth = @propGridManager.current_page.get_virtual_width newWidth = oldWidth Wx.NumberEntryDialog(self, "Enter virtual width (-1-2000).", "Width:", "Change Virtual Width", oldWidth, -1, 2000) do |dlg| newWidth = dlg.value if dlg.show_modal == Wx::ID_OK end if newWidth != oldWidth @propGridManager.grid.set_virtual_width(newWidth) end end def on_set_grid_disabled(evt) @propGridManager.enable(!evt.is_checked) end def on_misc(event) case event.id when ID::STATICLAYOUT wsf = @propGridManager.get_window_style_flag if event.is_checked @propGridManager.set_window_style_flag(wsf|Wx::PG::PG_STATIC_LAYOUT) else @propGridManager.set_window_style_flag(wsf&~(Wx::PG::PG_STATIC_LAYOUT)) end when ID::COLLAPSEALL pg = @propGridManager.grid pg.each_property(Wx::PG::PG_ITERATE_ALL) { |p| p.set_expanded(false) } pg.refresh_grid when ID::GETVALUES @storedValues = @propGridManager.grid.get_property_values("Test", @propGridManager.grid.root, Wx::PG::PG_KEEP_STRUCTURE|Wx::PG::PG_INC_ATTRIBUTES) when ID::SETVALUES if @storedValues && @storedValues.is_type("list") @propGridManager.grid.set_property_values(@storedValues) else Wx.message_box("First use Get Property Values.") end when ID::SETVALUES2 list = Wx::Variant.new([ Wx::Variant.new(1234, "VariantLong"), Wx::Variant.new(true,"VariantBool") ]) list.append(Wx::Variant.new("Test Text", "VariantString")) @propGridManager.grid.set_property_values(list) when ID::COLLAPSE # Collapses selected. selProp = @propGridManager.selection @propGridManager.collapse(selProp) if selProp when ID::RUNTESTFULL # Runs a regression test. run_tests(true) when ID::RUNTESTPARTIAL # Runs a regression test. run_tests(false) when ID::UNSPECIFY prop = @propGridManager.selection if prop @propGridManager.set_property_value_unspecified(prop) prop.refresh_editor end end end def on_populate_click(event) id = event.id @propGrid.clear @propGrid.freeze if id == ID::POPULATE1 populate_with_standard_items elsif id == ID::POPULATE2 populate_with_library_config end @propGrid.thaw end def on_set_spin_ctrl_editor_click(event) if Wx.has_feature? :USE_SPINBTN pgId = @propGridManager.get_selection if pgId @propGridManager.set_property_editor(pgId, Wx::PG::PG_EDITOR_SPIN_CTRL) else Wx.message_box("First select a property") end end end def on_test_replace_click(event) pgId = @propGridManager.selection if pgId choices = Wx::PG::PGChoices.new choices.add("Flag 0", 0x0001) choices.add("Flag 1", 0x0002) choices.add("Flag 2", 0x0004) choices.add("Flag 3", 0x0008) maxVal = 0x000F # Look for unused property name propName = "ReplaceFlagsProperty" idx = 0; while @propGridManager.get_property_by_name(propName) propName = "ReplaceFlagsProperty %i" % (idx += 1) end # Replace property and select new one # with random value in range [1..maxVal] propVal = Time.now.to_i % maxVal + 1 newId = @propGridManager.replace_property(pgId, Wx::FlagsProperty.new(propName, Wx::PG::PG_LABEL, choices, propVal)) @propGridManager.set_property_attribute(newId, Wx::PG::PG_BOOL_USE_CHECKBOX, true, Wx::PG::PG_RECURSE) @propGridManager.select_property(newId) else Wx.message_box("First select a property") end end def on_test_xrc(event) Wx.message_box("Sorry, not yet implemented") end def on_enable_common_values(event) prop = @propGridManager.selection if prop prop.enable_common_value else Wx.message_box("First select a property") end end def on_select_style(event) extraStyle = style = 0 names, values = %w[ PG_HIDE_CATEGORIES PG_AUTO_SORT PG_BOLD_MODIFIED PG_SPLITTER_AUTO_CENTER PG_TOOLTIPS PG_STATIC_SPLITTER PG_HIDE_MARGIN PG_LIMITED_EDITING PG_TOOLBAR PG_DESCRIPTION PG_NO_INTERNAL_BORDER ].inject([[],[]]) { |set, name| set[0] << "Wx::PG::#{name}"; set[1] << Wx::PG.const_get(name); set } flags = @propGridManager.get_window_style Wx.MultiChoiceDialog(self, "Select window styles to use", "wxPropertyGrid Window Style", names) do |dlg| sel = [] values.each_with_index { |val, ix| sel << ix if (flags & val) == val } dlg.set_selections(sel) return if dlg.show_modal == Wx::ID_CANCEL flags = 0 sel = dlg.selections sel.each { |ix| flags |= values[ix] } style = flags end names, values = %w[ PG_EX_INIT_NOCAT PG_EX_NO_FLAT_TOOLBAR PG_EX_MODE_BUTTONS PG_EX_HELP_AS_TOOLTIPS PG_EX_NATIVE_DOUBLE_BUFFERING PG_EX_AUTO_UNSPECIFIED_VALUES PG_EX_WRITEONLY_BUILTIN_ATTRIBUTES PG_EX_HIDE_PAGE_BUTTONS PG_EX_MULTIPLE_SELECTION PG_EX_ENABLE_TLP_TRACKING PG_EX_NO_TOOLBAR_DIVIDER PG_EX_TOOLBAR_SEPARATOR PG_EX_ALWAYS_ALLOW_FOCUS ].inject([[],[]]) { |set, name| set[0] << "Wx::PG::#{name}"; set[1] << Wx::PG.const_get(name); set } flags = @propGridManager.get_extra_style Wx.MultiChoiceDialog(self, "Select extra window styles to use", "wxPropertyGrid Extra Style", names) do |dlg| sel = [] values.each_with_index { |val, ix| sel << ix if (flags & val) == val } dlg.set_selections(sel) return if dlg.show_modal == Wx::ID_CANCEL flags = 0 sel = dlg.selections sel.each { |ix| flags |= values[ix] } extraStyle = flags end replace_grid(style, extraStyle) end def on_fit_columns_click(event) page = @propGridManager.get_current_page # Remove auto-centering @propGridManager.set_window_style(@propGridManager.get_window_style & ~Wx::PG::PG_SPLITTER_AUTO_CENTER) # Grow manager size just prior fit - otherwise # column information may be lost. oldGridSize = @propGridManager.grid.get_client_size oldFullSize = self.size self.size = ([1000, oldFullSize.height]) newSz = page.fit_columns dx = oldFullSize.width - oldGridSize.width; dy = oldFullSize.height - oldGridSize.height; newSz.inc_by(dx, dy) self.size = newSz end def on_change_flags_prop_items_click(event) p = @propGridManager.get_property_by_name("Window Styles") newChoices = Wx::PG::PGChoices.new newChoices.add("Fast",0x1) newChoices.add("Powerful",0x2) newChoices.add("Safe",0x4) newChoices.add("Sleek",0x8) p.set_choices(newChoices) end # def on_save_to_file_click(event) end # def on_load_from_file_click(event) end def on_set_property_value(event) pg = @propGridManager.grid selected = pg.selection if selected value = Wx.get_text_from_user("Enter new value:") pg.set_property_value(selected, value) end end def on_insert_choice(event) pg = @propGridManager.grid selected = pg.selection if selected choices = selected.choices if choices.ok? # Insert new choice to the center of list pos = choices.count / 2 selected.insert_choice("New Choice", pos) return end end Wx.message_box("First select a property with some choices.") end def on_delete_choice(event) pg = @propGridManager.grid selected = pg.selection if selected choices = selected.choices if choices.ok? # Deletes choice from the center of list pos = choices.count / 2 selected.delete_choice(pos) return end end Wx.message_box("First select a property with some choices.") end def on_insert_page(event) @propGridManager.add_page("New Page") end def on_remove_page(event) @propGridManager.remove_page(@propGridManager.get_selected_page) end def on_save_state(event) @savedState = @propGridManager.save_editable_state Wx.log_debug("Saved editable state string: \"%s\"", @savedState) end def on_restore_state(event) @propGridManager.restore_editable_state(@savedState) if @savedState end def on_run_minimal_click(event) PropGridMinimal.display_minimal_frame(self) end def iterate_message(prop) s = "\"%s\" class = %s, valuetype = %s" % [prop.label, prop.class.name, prop.value_type] Wx.message_box(s, "Iterating... (press CANCEL to end)", Wx::OK|Wx::CANCEL) end private :iterate_message def on_iterate1_click(event) @propGridManager.get_current_page.each_property do |p| break if iterate_message(p) == Wx::CANCEL end end def on_iterate2_click(event) @propGridManager.get_current_page.each_property(Wx::PG::PG_ITERATE_VISIBLE) do |p| break if iterate_message(p) == Wx::CANCEL end end def on_iterate3_click(event) @propGridManager.get_current_page.properties_reversed(Wx::PG::PG_ITERATE_DEFAULT).each do |p| break if iterate_message(p) == Wx::CANCEL end end def on_iterate4_click(event) @propGridManager.get_current_page.each_property(Wx::PG::PG_ITERATE_CATEGORIES) do |p| break if iterate_message(p) == Wx::CANCEL end end def on_extended_key_nav(event) # Use AddActionTrigger() and DedicateKey() to set up Enter, # Up, and Down keys for navigating between properties. propGrid = @propGridManager.grid propGrid.add_action_trigger(Wx::PG::PG_ACTION_NEXT_PROPERTY, Wx::K_RETURN) propGrid.dedicate_key(Wx::K_RETURN) # Up and Down keys are already associated with navigation, # but we must also prevent them from being eaten by # editor controls. propGrid.dedicate_key(Wx::K_UP) propGrid.dedicate_key(Wx::K_DOWN) end def on_property_grid_change(event) property = event.property name = property.name # Properties store values internally as wxVariants, but it is preferred # to use the more modern wxAny at the interface level in C++ # wxRuby however does not support wxAny and does not need to as Variants map # pretty seamless to Ruby value = property.value # Don't handle 'unspecified' values return if value.null? # Some settings are disabled outside Windows platform if name == "X" set_size(value.to_i, -1, -1, -1, Wx::SIZE_USE_EXISTING) elsif name == "Y" set_size(-1, value.to_i, -1, -1, Wx::SIZE_USE_EXISTING) elsif ( name == "Width" ) set_size(-1, -1, value.to_i, -1, Wx::SIZE_USE_EXISTING) elsif name == "Height" set_size( -1, -1, -1, value.to_i, Wx::SIZE_USE_EXISTING) elsif name == "Label" set_title(value.to_s) elsif name == "Font" font = value.font unless font.ok? Wx.message_box('Invalid font!') return end @propGridManager.set_font(font) elsif name == "Margin Colour" cpv = value.colour_property_value @propGridManager.grid.set_margin_colour(cpv.colour_) elsif name == "Cell Colour" cpv = value.colour_property_value @propGridManager.grid.set_cell_background_colour(cpv.colour_) elsif name == "Line Colour" cpv = value.colour_property_value @propGridManager.grid.set_line_colour(cpv.colour_) elsif name == "Cell Text Colour" cpv = value.colour_property_value @propGridManager.grid.set_cell_text_colour(cpv.colour_) end end def on_property_grid_changing(event) p = event.property if p.name == "Font" res = Wx.message_box("'%s' is about to change (to variant of type '%s')\n\nAllow or deny?" % [p.name, event.value.type], "Testing wxEVT_PG_CHANGING", Wx::YES_NO, @propGridManager) if res == Wx::NO Kernel.raise 'Must be able to Veto event' unless event.can_veto? event.veto # Since we ask a question, it is better if we omit any validation # failure behaviour. event.set_validation_failure_behavior(0) end end end def on_property_grid_select(event) property = event.property if property @itemEnable.enable(true) if property.enabled? @itemEnable.set_item_label("Disable") else @itemEnable.set_item_label("Enable") end else @itemEnable.enable(false) end if Wx.has_feature? :USE_STATUSBAR prop = event.property sb = self.status_bar if prop text = "Selected: " text << @propGridManager.get_property_label(prop) sb.set_status_text(text) end end end def on_property_grid_highlight(event) end def on_property_grid_item_right_click(event) if Wx.has_feature? :USE_STATUSBAR prop = event.property sb = self.status_bar if prop text = "Right-clicked: " text << prop.label text << ", name="; text << @propGridManager.get_property_name(prop) sb.set_status_text(text) else sb.set_status_text('') end end end def on_property_grid_item_double_click(event) if Wx.has_feature? :USE_STATUSBAR prop = event.property sb = self.status_bar if prop text = "Double-clicked: " text << prop.label text << ", name=" text << @propGridManager.get_property_name(prop) sb.set_status_text(text) else sb.set_status_text('') end end end def on_property_grid_page_change(event) if Wx.has_feature? :USE_STATUSBAR sb = self.status_bar text = "Page Changed: " text << @propGridManager.get_page_name(@propGridManager.get_selected_page) sb.set_status_text(text) end end def on_property_grid_button_click(event) if Wx.has_feature? :USE_STATUSBAR prop = @propGridManager.selection sb = self.status_bar if prop text = "Button clicked: " text << @propGridManager.get_property_label(prop) text << ", name=" text << @propGridManager.get_property_name(prop) sb.set_status_text(text) else Wx.message_box("SHOULD NOT HAPPEN!!!") end end end def on_property_grid_text_update(event) event.skip end def on_property_grid_key_event(event) end def on_property_grid_item_collapse(event) Wx.log_message("Item was Collapsed") end def on_property_grid_item_expand(event) Wx.log_message("Item was Expanded") end def on_property_grid_label_edit_begin(event) Wx.log_message("PG_EVT_LABEL_EDIT_BEGIN(%s)", event.property.label) end def on_property_grid_label_edit_ending(event) Wx.log_message("PG_EVT_LABEL_EDIT_ENDING(%s)", event.property.label) end def on_property_grid_col_begin_drag(event) if @itemVetoDragging.is_checked Wx.log_message("Splitter %i resize was vetoed", event.column) event.veto else Wx.log_debug("Splitter %i resize began", event.column) end end def on_property_grid_col_dragging(event) end def on_property_grid_col_end_drag(event) Wx.log_debug("Splitter %i resize ended", event.column) end def on_about(event) toolkit = "%s %i.%i.%i" % [Wx::PlatformInfo.get_port_id_name, Wx::PlatformInfo.get_toolkit_major_version, Wx::PlatformInfo.get_toolkit_minor_version, Wx::PlatformInfo.get_toolkit_micro_version] msg = ("wxRuby PropertyGrid Sample" + if Wx::WXWIDGETS_VERSION >= '3.3.0' || Wx.has_feature?(:USE_UNICODE) if Wx.has_feature?(:USE_UNICODE_UTF8) && Wx.has_feature?(:USE_UNICODE_UTF8) " " else " " end else " " end + if Wx::DEBUG " " else " " end + "\n\n" + "Programmed by %s\n\n" + "Using wxRuby %s (wxWidgets %s; %s)\n\n") % ["Martin Corino (C++ original by Jaakko Salli)", Wx::WXRUBY_VERSION, Wx::WXWIDGETS_VERSION, toolkit] Wx.message_box(msg, "About", Wx::OK | Wx::ICON_INFORMATION, self) end def on_move(event) unless @propGridManager # this check is here so the frame layout can be tested # without creating propertygrid event.skip return end # Update position properties pos = get_position # Must check if properties exist (as they may be deleted). # Using m_pPropGridManager, we can scan all pages automatically. id = @propGridManager.get_property_by_name("X") @propGridManager.set_property_value(id, pos.x) if id id = @propGridManager.get_property_by_name("Y") @propGridManager.set_property_value( id, pos.y) if id id = @propGridManager.get_property_by_name("Position") @propGridManager.set_property_value(id, pos) if id # Should always call event.skip in frame's MoveEvent handler event.skip end def on_resize(event) unless @propGridManager # this check is here so the frame layout can be tested # without creating propertygrid event.skip return end # Update size properties sz = get_size # Must check if properties exist (as they may be deleted). # Using m_pPropGridManager, we can scan all pages automatically. p = @propGridManager.get_property_by_name("Width") @propGridManager.set_property_value(p, sz.width) if p && !p.is_value_unspecified p = @propGridManager.get_property_by_name("Height") @propGridManager.set_property_value(p, sz.height) if p && !p.is_value_unspecified id = @propGridManager.get_property_by_name("Size") @propGridManager.set_property_value(id, sz) if id # Should always call event.skip in frame's SizeEvent handler event.skip end def on_idle(event) event.skip end def on_show_popup(event) if @popup @popup.destroy @popup = nil return end @popup = PropertyGridPopup.new(self) pt = Wx.get_mouse_position @popup.position(pt, [0, 0]) @popup.show end def add_test_properties(pg) pg.append(MyColourProperty.new("CustomColourProperty", Wx::PG::PG_LABEL, Wx::GREEN)) pg.get_property("CustomColourProperty").set_auto_unspecified(true) pg.set_property_editor("CustomColourProperty", Wx::PG::PG_EDITOR_COMBO_BOX) pg.set_property_help_string("CustomColourProperty", "This is a MyColourProperty from the sample app. "+ "It is built by subclassing wxColourProperty.") end def run_tests(fullTest, interactive = false) end end end module PropgridSample include WxRuby::Sample if defined? WxRuby::Sample def self.describe { file: __FILE__, summary: 'wxRuby PropGrid example.', description: 'wxRuby PropGrid example displaying frame showcasing PropgridManager.' } end def self.activate frameSize = Wx::Size.new((Wx::SystemSettings.get_metric(Wx::SYS_SCREEN_X) / 10) * 4, (Wx::SystemSettings.get_metric(Wx::SYS_SCREEN_Y) / 10) * 8) frameSize.width = 500 if frameSize.width > 500 frame = PropGrid::FormMain.new("wxPropertyGrid Sample", [0,0], frameSize) frame.show(true) frame end if $0 == __FILE__ Wx::App.run do gc_stress PropgridSample.activate end end end