# Copyright (c) 2023 M.J.N. Corino, The Netherlands # # This software is released under the MIT license. # # Some parts are # Copyright 2004-2007, wxRuby development team # released under the MIT-like wxRuby2 license ### require 'wx' module HTLBox # to use Wx::HtmlListBox you must derive a new class from it as you must # implement virtual on_get_item class MyHtmlListBox < Wx::HTML::HtmlListBox def initialize(parent, multi = false) super(parent, style: multi ? Wx::LB_MULTIPLE : 0) # flag telling us whether we should use fg colour even for the selected # item @change = false # flag which we toggle to update the first items text in on_get_item() @first_item_updated = false @link_clicked = false set_margins(5, 5) set_item_count(1000) set_selection(3) end attr_accessor :link_clicked def set_change_sel_fg(change) @change = change end def update_first_item @first_item_updated = !@first_item_updated refresh_row(0) end protected # override this method to return data to be shown in the listbox (this is # mandatory) def on_get_item(n) return '

Just updated

' if n == 0 && @first_item_updated level = n % 6 + 1 clr = Wx::Colour.new((n - 192).abs % 256, (n - 256).abs % 256, (n - 128).abs % 256) label = "Item #{n}" if n == 1 if !@link_clicked label += "Click here..." else label += "Clicked here..." end end label end # change the appearance by overriding these functions (this is optional) def on_draw_separator(dc, rect, _) if get_parent.menu_bar.is_checked(MyFrame::ID::HtmlLbox_DrawSeparator) dc.with_pen(Wx::BLACK_DASHED_PEN) do dc.draw_line(rect.x, rect.y, rect.right, rect.y) dc.draw_line(rect.x, rect.bottom, rect.right, rect.bottom) end end end def get_selected_text_colour(col_fg) @change ? super : col_fg end end class MyFrame < Wx::Frame # IDs for the controls and the menu commands module ID include Wx::IDHelper # menu items HtmlLbox_CustomBox = self.next_id HtmlLbox_SimpleBox = self.next_id HtmlLbox_Quit = self.next_id HtmlLbox_SetMargins = self.next_id HtmlLbox_DrawSeparator = self.next_id HtmlLbox_ToggleMulti = self.next_id HtmlLbox_SelectAll = self.next_id HtmlLbox_UpdateItem = self.next_id HtmlLbox_GetItemRect = self.next_id HtmlLbox_SetBgCol = self.next_id HtmlLbox_SetSelBgCol = self.next_id HtmlLbox_SetSelFgCol = self.next_id HtmlLbox_Clear = self.next_id # it is important for the id corresponding to the "About" command to have # this standard value as otherwise it won't be handled properly under Mac # (where it is special and put into the "Apple" menu) HtmlLbox_About = Wx::ID_ABOUT end Wx::ArtLocator.add_search_path(File.dirname(__dir__)) def initialize super(nil, title: 'HtmlLbox wxWidgets Sample',size: [500, 500]) # set the frame icon set_icon(Wx::Icon(:sample)) if Wx.has_feature?(:USE_MENUS) # create a menu bar menu_file = Wx::Menu.new menu_file.append_radio_item(ID::HtmlLbox_CustomBox, "Use custom box", "Use a wxHtmlListBox virtual class control") menu_file.append_radio_item(ID::HtmlLbox_SimpleBox, "Use simple box", "Use a wxSimpleHtmlListBox control") menu_file.append_separator menu_file.append(ID::HtmlLbox_Quit, "E&xit\tAlt-X", "Quit this program") # create our specific menu menu_hl_box = Wx::Menu.new menu_hl_box.append(ID::HtmlLbox_SetMargins, "Set &margins...\tCtrl-G", "Change the margins around the items") menu_hl_box.append_check_item(ID::HtmlLbox_DrawSeparator, "&Draw separators\tCtrl-D" , "Toggle drawing separators between cells") menu_hl_box.append_separator menu_hl_box.append_check_item(ID::HtmlLbox_ToggleMulti, "&Multiple selection\tCtrl-M", "Toggle multiple selection on/off") menu_hl_box.append_separator menu_hl_box.append(ID::HtmlLbox_SelectAll, "Select &all items\tCtrl-A") menu_hl_box.append(ID::HtmlLbox_UpdateItem, "Update &first item\tCtrl-U") menu_hl_box.append(ID::HtmlLbox_GetItemRect, "Show &rectangle of item #10\tCtrl-R") menu_hl_box.append_separator menu_hl_box.append(ID::HtmlLbox_SetBgCol, "Set &background...\tCtrl-B") menu_hl_box.append(ID::HtmlLbox_SetSelBgCol, "Set &selection background...\tCtrl-S") menu_hl_box.append_check_item(ID::HtmlLbox_SetSelFgCol, "Keep &foreground in selection\tCtrl-F") menu_hl_box.append_separator menu_hl_box.append(ID::HtmlLbox_Clear, "&Clear\tCtrl-L") # the "About" item should be in the help menu help_menu = Wx::Menu.new help_menu.append(ID::HtmlLbox_About, "&About\tF1", "Show about dialog") # now append the freshly created menu to the menu bar... mbar = Wx::MenuBar.new mbar.append(menu_file, "&File") mbar.append(menu_hl_box, "&Listbox") mbar.append(help_menu, "&Help") mbar.check(ID::HtmlLbox_DrawSeparator, true) # ... and attach this menu bar to the frame self.menu_bar = mbar end # USE_MENUS if Wx.has_feature?(:USE_STATUSBAR) # create a status bar just for fun (by default with 1 pane only) create_status_bar(2) set_status_text("Welcome to wxWidgets!") end # USE_STATUSBAR # create the child controls create_box text = Wx::TextCtrl.new(self, Wx::ID_ANY, "", style: Wx::TE_MULTILINE) old_log_tgt = Wx::Log.set_active_target(Wx::LogTextCtrl.new(text)) # and lay them out sizer = Wx::HBoxSizer.new sizer.add(@hlbox, 2, Wx::GROW) sizer.add(text, 3, Wx::GROW) self.sizer = sizer evt_menu ID::HtmlLbox_CustomBox, :on_simple_or_custom_box evt_menu ID::HtmlLbox_SimpleBox, :on_simple_or_custom_box evt_menu ID::HtmlLbox_Quit, :on_quit evt_close { Wx::Log.set_active_target(old_log_tgt); destroy } evt_menu ID::HtmlLbox_SetMargins, :on_set_margins evt_menu ID::HtmlLbox_DrawSeparator, :on_draw_separator evt_menu ID::HtmlLbox_ToggleMulti, :on_toggle_multi evt_menu ID::HtmlLbox_SelectAll, :on_select_all evt_menu ID::HtmlLbox_UpdateItem, :on_update_item evt_menu ID::HtmlLbox_GetItemRect, :on_get_item_rect evt_menu ID::HtmlLbox_About, :on_about evt_menu ID::HtmlLbox_SetBgCol, :on_set_bg_col evt_menu ID::HtmlLbox_SetSelBgCol, :on_set_sel_bg_col evt_menu ID::HtmlLbox_SetSelFgCol, :on_set_sel_fg_col evt_menu ID::HtmlLbox_Clear, :on_clear evt_update_ui ID::HtmlLbox_SelectAll, :on_update_ui_select_all evt_listbox Wx::ID_ANY, :on_lbox_select evt_listbox_dclick Wx::ID_ANY, :on_lbox_d_click # the HTML listbox's events evt_html_link_clicked Wx::ID_ANY, :on_html_link_clicked evt_html_cell_hover Wx::ID_ANY, :on_html_cell_hover evt_html_cell_clicked Wx::ID_ANY, :on_html_cell_clicked end # event handlers def on_simple_or_custom_box(event) old = @hlbox # we need to recreate the listbox create_box get_sizer.replace(old, @hlbox) old.destroy get_sizer.layout refresh end def on_quit(event) # true is to force the frame to close close(true) end def on_about(event) Wx.message_box("This sample shows Wx::HtmlListBox class.\n"+ "\n"+ "(c) 2023 Martin Corino\n" + "(original (c) 2003 Vadim Zeitlin)\n", "About HtmlLbox", Wx::OK | Wx::ICON_INFORMATION, self) end def on_set_margins(event) margin = Wx.get_number_from_user( "Enter the margins to use for the listbox items.", "Margin: ", "HtmlLbox: Set the margins", 0, 0, 20, self) if margin != -1 @hlbox.set_margins(margin, margin) @hlbox.refresh_all end end def on_draw_separator(_event) @hlbox.refresh_all end def on_toggle_multi(event) old = @hlbox # we need to recreate the listbox create_box get_sizer.replace(old, @hlbox) old.destroy get_sizer.layout end def on_select_all(event) @hlbox.select_all end def on_update_item(event) @hlbox.update_first_item if @hlbox.is_a?(MyHtmlListBox) end def on_get_item_rect(event) r = @hlbox.get_item_rect(10) Wx.log_message("Rect of item %d: (%d, %d)-(%d, %d)", 10, r.x, r.y, r.x + r.width, r.y + r.height) end def on_set_bg_col(event) col = Wx.get_colour_from_user(self, @hlbox.get_background_colour) if col.ok? @hlbox.set_background_colour(col) @hlbox.refresh if Wx.has_feature?(:USE_STATUSBAR) set_status_text("Background colour changed.") end # wxUSE_STATUSBAR end end def on_set_sel_bg_col(event) col = Wx.get_colour_from_user(self, @hlbox.get_selection_background) if col.ok? @hlbox.set_selection_background(col) @hlbox.refresh if Wx.has_feature?(:USE_STATUSBAR) set_status_text("Selection Background colour changed.") end # wxUSE_STATUSBAR end end def on_set_sel_fg_col(event) if @hlbox.is_a?(MyHtmlListBox) @hlbox.set_change_sel_fg(!event.checked?) @hlbox.refresh end end def on_clear(event) @hlbox.clear end def on_update_ui_select_all(event) event.enable(@hlbox && @hlbox.has_multiple_selection) end def on_lbox_select(event) Wx.log_message("Listbox selection is now %d.", event.get_int) if @hlbox.has_multiple_selection s = '' @hlbox.each_selected do |item| s << ', ' unless s.empty? s << item.to_s end Wx.log_message("Selected items: #{s}") unless s.empty? end if Wx.has_feature?(:USE_STATUSBAR) set_status_text("# items selected = #{@hlbox.get_selected_count}") end # wxUSE_STATUSBAR end def on_lbox_d_click(event) Wx.log_message("Listbox item #{event.get_int} double clicked.") end def on_html_link_clicked(event) Wx.log_message("The url '%s' has been clicked!", event.get_link_info.get_href) if @hlbox.is_a?(MyHtmlListBox) @hlbox.link_clicked = true @hlbox.refresh_row(1) end end def on_html_cell_hover(event) Wx.log_message("Mouse moved over cell %s at %d;%d", event.get_cell.id, event.get_point.x, event.get_point.y) end def on_html_cell_clicked(event) Wx.log_message("Click over cell %s at %d;%d", event.get_cell.id, event.get_point.x, event.get_point.y) # if we don't skip the event, OnHtmlLinkClicked won't be called! event.skip end def create_box multi = get_menu_bar.is_checked(ID::HtmlLbox_ToggleMulti) if get_menu_bar.is_checked(ID::HtmlLbox_CustomBox) @hlbox = MyHtmlListBox.new(self, multi) else # simple listbox @hlbox = Wx::HTML::SimpleHtmlListBox.new(self, style: multi ? Wx::LB_MULTIPLE : 0) # unlike Wx::HTML::HtmlListBox which is abstract, Wx::HTML::SimpleHtmlListBox is a # concrete control and doesn't support virtual mode, this we need # to add all of its items from the beginning arr = [] 1000.times do |n| clr = Wx::Colour.new((n - 192).abs % 256, (n - 256).abs % 256, (n - 128).abs % 256) level = n % 6 + 1 label = "Item #{n}" arr << label end @hlbox.append(arr) end end end end module HtmlListBoxSample include WxRuby::Sample if defined? WxRuby::Sample def self.describe { file: __FILE__, summary: 'wxRuby HtmlListBox control example.', description: "wxRuby example showcasing the HtmlListBox controls.\n"+ " - Wx::HtmlListBox\n"+ " - Wx::SimpleHtmlListBox\n" } end def self.activate frame = HTLBox::MyFrame.new frame.show frame end if $0 == __FILE__ Wx::App.run { HtmlListBoxSample.activate } end end