### # PropertyGrid extended sample # Copyright (c) M.J.N. Corino, The Netherlands ### require 'wx' require_relative './propgrid_minimal' # ----------------------------------------------------------------------- # 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 %i[ PGID ABOUT QUIT APPENDPROP APPENDCAT INSERTPROP INSERTCAT ENABLE SETREADONLY HIDE BOOL_CHECKBOX DELETE DELETER DELETEALL UNSPECIFY ITERATE1 ITERATE2 ITERATE3 ITERATE4 CLEARMODIF FREEZE DUMPLIST COLOURSCHEME1 COLOURSCHEME2 COLOURSCHEME3 CATCOLOURS SETBGCOLOUR SETBGCOLOURRECUR STATICLAYOUT POPULATE1 POPULATE2 COLLAPSE COLLAPSEALL GETVALUES SETVALUES SETVALUES2 RUNTESTFULL RUNTESTPARTIAL FITCOLUMNS CHANGEFLAGSITEMS TESTINSERTCHOICE TESTDELETECHOICE INSERTPAGE REMOVEPAGE SETSPINCTRLEDITOR SETPROPERTYVALUE TESTREPLACE SETCOLUMNS SETVIRTWIDTH SETPGDISABLED TESTXRC ENABLECOMMONVALUES SELECTSTYLE SAVESTATE RESTORESTATE RUNMINIMAL ENABLELABELEDITING VETOCOLDRAG ONEXTENDEDKEYNAV SHOWPOPUP POPUPGRID ].each_with_index { |sym, ix| self.const_set(sym, ix+1) } if Wx.has_feature?(:USE_HEADERCTRL) SHOWHEADER = POPUPGRID+1 end COLOURSCHEME4 = 100 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') 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) mdc = Wx::MemoryDC.new(myTestBitmap1x) 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) myTestBitmap2x = Wx::Bitmap.new(120, 30, 32) mdc = Wx::MemoryDC.new(myTestBitmap2x) 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) 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) 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 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 = 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