#!/usr/pkg/bin/ruby27
# wxRuby2 Sample Code. Copyright (c) 2004-2008 wxRuby development team
# Freely reusable code: see SAMPLES-LICENSE.TXT for details
begin
  require 'rubygems' 
rescue LoadError
end
require 'wx'

# Demo created by Robert Carlin, based on the wxPython demo by Robin Dunn
# Modified by Kevin Smith, Roy Sutton, Alex Fenton


#  TODO:
#    Finish Scintilla integration
#    Fix 'Find Next'
#    Refactor editor pane
#    More samples
#    Finish 'rubification' of source
#    Fix non-scintilla code viewer

OVR_TEXT = "This is the WxRuby Demo.  It was ported from the wxPython Demo, created by Robin Dunn.  Many thanks to him for all his hard work - this demo is what it is because of him.  Click on any of the items in the tree control to start the demo.  Don't forget to check out the Demo Code tab - you can see the source code for each demo!\nHope you like it!"

$tree_list = [
    #new stuff
    #['Recent Additions', [
    #    'wxMaskedNumCtrl',
    #    'FloatCanvas',
    #    ]],

    # managed windows == things with a [optional] caption you can close
    ['Base Frames and Dialogs', [
        'wxDialog',
        'wxFrame',
        'wxMDIWindows',
        'wxMiniFrame',
        #'wxWizard',
        ]],

    # the common dialogs
    ['Common Dialogs', [
        'wxColourDialog',
        'wxDirDialog',
        'wxFileDialog',
        'wxFileDialog_Save',
        'wxFindReplaceDialog',
        'wxFontDialog',
        'wxMessageDialog',
        #'wxPageSetupDialog',
        #'wxPrintDialog',
        'wxProgressDialog',
        'wxSingleChoiceDialog',
        'wxTextEntryDialog',
        ]],

    # dialogs from libraries
    ['More Dialogs', [
    #    'ErrorDialogs',
    #    'ImageBrowser',
        'wxMultipleChoiceDialog',
        'wxScrolledMessageDialog'
        ]],

    # core controls
    ['Core Windows/Controls', [
        'PopupMenu',
        'wxBitmapButton',
        'wxButton',
        'wxCheckBox',
        'wxCheckListBox',
        'wxChoice',
        'wxChoicebook',
        'wxComboBox',
        'wxGauge',
        'wxGenericDirCtrl',
        'wxGrid',
        #'wxGrid_MegaExample',
        'wxListBox',
        #'wxListCtrl',
        'wxListCtrl_virtual',
        'wxMenu',
        'wxNotebook',
        #'wxPopupWindow',
        'wxRadioBox',
        'wxRadioButton',
        'wxSashWindow',
        'wxScrolledWindow',
        'wxSlider',
        'wxSpinButton',
        'wxSpinCtrl',
        'wxSplitterWindow',
        'wxStaticBitmap',
        'wxStaticText',
        'wxStatusBar',
        'wxTextCtrl',
        'wxToggleButton',
        'wxToolBar',
        'wxTreeCtrl',
        #'wxValidator',
        ]],

    # controls coming from other libraries
    ['More Windows/Controls', [
        #'wxFloatBar',          deprecated
        #'wxMVCTree',           deprecated
        #'wxRightTextCtrl',     deprecated as we have wxTE_RIGHT now.
        #'AnalogClockWindow',
        #'ColourSelect',
        #'ContextHelp',
        #'FancyText',
        #'FloatCanvas',
        #'FileBrowseButton',
        #'GenericButtons',
        #'MaskedEditControls',
        #'SplitTree',
        #'TablePrint',
        #'Throbber',
        #'wxCalendar',
        'wxCalendarCtrl',
        #'wxDynamicSashWindow',
        #'wxEditableListBox',
        #'wxEditor',
        #'wxHtmlWindow',
        #'wxIEHtmlWin',
        #'wxIntCtrl',
        #'wxLEDNumberCtrl',
        #'wxMimeTypesManager',
        #'wxMaskedNumCtrl',
        #'wxMultiSash',
        #'wxPopupControl',
        #'wxStyledTextCtrl_1',
        #'wxStyledTextCtrl_2',
        #'wxTimeCtrl',
        #'wxTreeListCtrl',
        ]],

    # How to lay out the controls in a frame/dialog
    ['Window Layout', [
    #    'LayoutAnchors',
    #    'Layoutf',
    #    'RowColSizer',
        'Sizers',
    #    'wxScrolledPanel',
    #    'wxXmlResource',
    #    'wxXmlResourceHandler',
        ]],

    # ditto
    #['Process and Events', [
    #    'EventManager',
    #   'infoframe',
    #    'OOR',
    #    'PythonEvents',
    #    'Threads',
    #    'wxKeyEvents',
    #    'wxProcess',
    #    'wxTimer',
    #    ]],

    #~ # Clipboard and DnD
    #~ ['Clipboard and DnD', [
        #~ #'CustomDragAndDrop',
        #~ 'DragAndDrop',
        #~ 'URLDragAndDrop',
        #~ ]],

    # Images
    ['Using Images', [
    #    'Throbber',
        'wxArtProvider',
        'wxCursor',
        'wxDragImage',
    #    'wxImage',
    #    'wxImageFromStream',
    #    'wxMask',
        ]],

    # Other stuff
    ['Miscellaneous', [
    #    'ColourDB',
    #    'DialogUnits',
    #    'DrawXXXList',
    #    'FontEnumerator',
    #    'PrintFramework',
         'ShapedWindow',
    #    'Throbber',
    #    'Unicode',
    #    'wxFileHistory',
    #    'wxJoystick',
    #    'wxOGL',
    #    'wxWave',
        ]],

    # need libs not coming with the demo
    #['Objects using an external library', [
    #    'ActiveXWrapper_Acrobat',
    #    'ActiveXWrapper_IE',
    #    'wxGLCanvas',
    #    'wxPlotCanvas',
    #    ]],


    ['Check out the samples dir too', [
        ]],

]

class DemoCodeViewer < Wx::TextCtrl
    def intialize(parent, id)
        super(parent, id, OVR_TEXT, Wx::DEFAULT_POSITION, Wx::Size.new(400, 400), 
              Wx::TE_MULTILINE|Wx::TE_READONLY|Wx::HSCROLL|
              Wx::TE_RICH|Wx::TE_NOHIDESEL)
    end
end

class WxRubyDemo < Wx::Frame
    attr_accessor :otherWin
    
    def initialize(title, pos, size, style=Wx::DEFAULT_FRAME_STYLE)
	    super(nil,-1,title,pos,size,style)
        @demoID = 6000
        @otherWin = nil
        
        icon_file = File.join(File.dirname(__FILE__), 'icons', 'mondrian.xpm')
        icon = Wx::Icon.new(icon_file, Wx::BITMAP_TYPE_XPM)
        set_icon(icon)

        @tbicon = DemoTaskBarIcon.new(self)
        
        evt_idle {|event| on_idle(event)}
        evt_close {|event| on_close(event)}
        evt_iconize {|event| on_iconize(event)}
        evt_maximize {|event| on_maximize(event)}
        
        centre(Wx::BOTH)
        create_status_bar(1, Wx::ST_SIZEGRIP)
        set_status_text("Welcome to the WxRuby Demo!")
        
        splitter = Wx::SplitterWindow.new(self, -1)
        splitter2 = Wx::SplitterWindow.new(splitter, -1)
        
        # Make a File menu
        
        @mainmenu = Wx::MenuBar.new
        menu = Wx::Menu.new
        menu.append(Wx::ID_EXIT, "E&xit\tALT-X", "Get the heck outta here!")
        evt_menu(Wx::ID_EXIT) {exit}
        @mainmenu.append(menu, "&File")
        
        # Make a Demo menu - thanks to Kevin Smith for figuring the submenus out!
        menu = Wx::Menu.new
        $tree_list.each do |item|
            @submenu = Wx::Menu.new
            item[1].each do |childItem|
                mID = @demoID += 1
                @submenu.append(mID, childItem)
                evt_menu(mID) {|event| on_demo_menu(childItem)}
            end
            menuItem = Wx::MenuItem.new(menu, 500000, item[0], "", Wx::ITEM_NORMAL, @submenu)
            menu.append_item(menuItem)
        end
        @mainmenu.append(menu, "&Demo")
        
        # Make a Help menu
        helpID = Wx::ID_ABOUT
        findID = @demoID += 1
        findnextID = @demoID += 1
        clearID = @demoID += 1
        menu = Wx::Menu.new
        menu.append(findID, "&Find\tCtrl-F", "Find in the Demo Code")
        menu.append(findnextID, "Find &Next\tF3", "Find Next")
        menu.append_separator
        menu.append(helpID, "&About\tCtrl-H", "wxRuby RULES!!!")
        evt_menu(helpID) {|event| on_help_about(event)}
        evt_menu(findID) {|event| on_help_find(event)}
        evt_menu(findnextID) {|event| on_find_next(event)}
        evt_find(-1) {|event| on_find(event)}
        evt_find_next(-1) {|event| on_find(event)}
        evt_find_close(-1) {|event| on_find_close(event)}
        @mainmenu.append(menu, "&Help")
        set_menu_bar(@mainmenu)
        
        @finddata = Wx::FindReplaceData.new()
        
        @treeMap = {}
        @tree = Wx::TreeCtrl.new(splitter)
        root = @tree.add_root("wxRuby Overview")
        firstChild = nil
        
        $tree_list.each do |item|
            child = @tree.append_item(root, item[0])
            if not firstChild then firstChild = child end
            item[1].each do |childItem|
                theDemo = @tree.append_item(child, childItem)
                @treeMap[childItem] = theDemo
            end
        end
        @tree.expand(root)
        @tree.expand(firstChild)
        
        evt_tree_item_expanded   @tree, :on_item_expanded
        evt_tree_item_collapsed  @tree, :on_item_collapsed
        evt_tree_sel_changed     @tree, :on_tree_sel_changed
        evt_tree_item_activated  @tree, :on_tree_sel_changed
        @tree.evt_left_down method(:on_tree_left_down)
        
        
        
        # Create a Notebook
        @nb = Wx::Notebook.new(splitter2, :style => Wx::CLIP_CHILDREN)
        
        @ovr = Wx::TextCtrl.new(@nb, :value => OVR_TEXT, :style =>
                                Wx::TE_MULTILINE|Wx::TE_READONLY|
                                Wx::TE_RICH|Wx::TE_NOHIDESEL)
        @nb.add_page(@ovr, "Overview")
        
        if Wx.const_defined?(:Scintilla)
          panel, @txt = setup_editor(@nb)
          @nb.add_page(panel, "Demo Code")
        else
          # FIXME: Should use DemoCodeViewer, but when we do (on Windows) it
          #         puts all text on one line!  Can remove instance_eval
          #         once that's resolved
          @txt = Wx::TextCtrl.new(@nb, :value => OVR_TEXT, :style =>
                                   Wx::TE_MULTILINE|Wx::TE_READONLY|
                                   Wx::HSCROLL|Wx::TE_RICH|Wx::TE_RICH2|
                                   Wx::TE_NOHIDESEL)
          @txt.instance_eval { alias clear_all clear }
          @txt.set_max_length(0)
          @nb.add_page(@txt, "Demo Code")
        end
        
        get_demo_file(__FILE__)
        
        @log = Wx::TextCtrl.new(splitter2, -1, "", Wx::DEFAULT_POSITION, 
                                Wx::DEFAULT_SIZE, 
                                Wx::TE_MULTILINE|Wx::TE_READONLY|Wx::HSCROLL)
        # For some reason when the number of characters entered is
        # greater than about 10,700, the text control freezes.  I know  
        # someone mentioned this on the list a while ago...calling
        # set_max_length(0) with zero as the argument tells the text 
        # control to default limit that the underlying native text
        # control can handle. 
        @log.set_max_length(0)
        Wx::Log::set_active_target(Wx::LogTextCtrl.new(@log))
        
        splitter.split_vertically(@tree, splitter2, 220)
        splitter2.split_horizontally(@nb, @log, 300)

        
        splitter.set_minimum_pane_size(20)        
        splitter2.set_minimum_pane_size(100)
        
        @nb.set_selection(0)
        @tree.select_item(root)
        show_tip()
    end
    
    def write_text(text)
        Wx::log_message(text)
    end
    
    def on_idle(event)
        if @otherWin != nil
            @otherWin.raise()
            @window = @otherWin
            @otherWin = nil
        end
    end
    
    def on_close(event)
        @tbicon.remove_icon
        destroy()
        exit()
    end
    
    def on_item_expanded(event)
        item = event.get_item()
        Wx::log_message("on_item_expanded: %s" % @tree.get_item_text(item))
    end
    
    def on_item_collapsed(event)
        item = event.get_item()
        Wx::log_message("on_item_collapsed: %s" % @tree.get_item_text(item))
    end
    
    def on_tree_sel_changed(event)

        item = event.get_item()

        if item.nonzero?
          itemText = @tree.get_item_text(item)
          run_demo(itemText)
        end
    end
    
    def on_tree_left_down(event)
        pt = Wx::Point.new(event.get_x, event.get_y)
        item = @tree.hit_test(pt)
        if item == @tree.get_selection()
            set_overview(@tree.get_item_text(item) + " Overview", @curOverview)
            Wx::log_message(@tree.get_item_text(item) + " Overview")

        end

        event.skip()
    end
    
    def run_demo(itemText)
        if @nb.get_page_count() == 3
            if @nb.get_selection() == 2
                @nb.set_selection(0)
            end
            if @window != nil
                @window = nil
            end
            @nb.delete_page(2)
        end
        
        if itemText == "wxRuby Overview"
            get_demo_file(__FILE__)
            set_overview("wxRuby Overview", OVR_TEXT)
            @nb.refresh()
            @window = nil       
        else
          demo_file = File.join( File.dirname(__FILE__), itemText + '.rbw')
            if File.exist?(demo_file)
                Wx::log_message("Running Demo: " + itemText + ".rbw")
                get_demo_file(demo_file)
                # I use load() here because it allows the user to modify
                # the underlying file for each sample, so that each time 
                # They run it any changes made will be reflected without
                # having to restart the demo. 
                begin
                    load demo_file
                    set_overview(itemText + " Overview", Demo::overview)
                    @tree.refresh()
                    @nb.refresh()
                    @window = Demo.run(self, @nb, self)
                    if @window.class.ancestors.include?(Wx::Window)
                        # Check to see if the demo returned a Wx::Window, Wx::Panel or a new class inheriting from them
                        # if so, create a new tab in the notebook for them
                        @nb.add_page(@window, "Demo")
                        @nb.set_selection(2)
                        @nb.refresh()
                    end
                rescue Exception => problem
                    dlg = Wx::MessageDialog.new(self, "A problem occurred with the %s demo:\n%s\n%s" % [itemText, problem, problem.backtrace().join("\n").to_s()], 
                                                "Error!!!", Wx::OK | Wx::ICON_ERROR)
                    dlg.show_modal()
                    dlg.destroy()
                end
            else
                @ovr.set_value("")
                @txt.clear_all
                @window = nil
            end
        end
        @tree.set_focus()
    end
    
    def get_demo_file(fileName)
        @filename = fileName
        @txt.clear()
        @txt.load_file(fileName)
        if @txt.is_a?(Wx::TextCtrl)
          @txt.set_insertion_point(0)
          @txt.show_position(0)
        end
    end
    
    def set_overview(name, text)
        text ||= ''
        @curOverview = text
        @ovr.set_value(text)
        @ovr.set_style(0,text.length,Wx::TextAttr.new(Wx::BLUE, Wx::Colour.new("White"), Wx::Font.new(12, Wx::FONTFAMILY_SWISS, Wx::FONTSTYLE_NORMAL, Wx::FONTWEIGHT_BOLD)))
        @nb.set_page_text(0, name)
    end
    
    # Menu Methods
    
    def on_file_exit(event)
        close()
    end
    
    def on_help_about(event)
        load File.join(File.dirname(__FILE__), "About.rbw")
        about = About::MyAboutBox.new(self)
        about.show_modal()
        about.destroy()
    end
    
    def on_help_find(event)
        @nb.set_selection(1)
        @finddlg = Wx::FindReplaceDialog.new(self, @finddata, "Find", Wx::FR_NOUPDOWN | Wx::FR_NOMATCHCASE | Wx::FR_NOWHOLEWORD)
        @finddlg.show()
    end
    
    def on_find(event)
        # FIXME: These problems are probably resolved now
        # Problems
        # 1) For some reason, the control is not properly counting EOL characters - it almost seems to be skipping them
        #    causing the control to incorrectly set the initial insertion point for the the "found" text
        # 2) This also is causing problems with the amount of text that is highlighted - the length of the highlighted string
        #    is less than it should be 
        # 3) After doing an initial "find" operation, using the "find next" operation causes the program to crash - again, I
        #    don't know why this is :(
        # Example - When I try to find "menu", the text that gets highlighted is the newline on the second line and the "ME" of 
        #           MENU_EXIT - a total of only 3 characters, when it should highlight all of "menu".  I don't fully understand
        #           this problem, but it doesn't appear until after you attempt to find text beyond the first line :(
        if @txt.is_a?(Wx::TextCtrl)
          @nb.set_selection(1)
          myEnd = @txt.get_last_position()
          write_text("Last position = %d" % myEnd)
          textstring = @txt.get_range(0,myEnd).downcase()
          if Wx::PLATFORM == "WXMSW"
              textstring.sub!(/\n/, "\r\n")
          end
          #write_text("textstring - %s" % textstring)
          start = @txt.get_insertion_point()
          write_text("insertion point = " + start.to_s())
          findstring = @finddata.get_find_string().downcase()
          write_text("finddata = " + findstring)
          loc = textstring.index(findstring, start)
          write_text("location = " + loc.to_s())
          write_text("findstring.length() = " + findstring.length().to_s())
          if loc == nil and start != 0
            # string not found, start at beginning
            start = 0
            loc = textstring.index(findstring, start)
          end
        
          if loc == nil
            dlg = Wx::MessageDialog.new(self, 'Find String Not Found', 'Find String Not Found in Demo File',
                                          Wx::OK | Wx::ICON_INFORMATION)
            dlg.show_modal()
            dlg.destroy()
          end
        
          if @finddlg
            if loc == nil
                @finddlg.set_focus()
                return
            else
                @finddlg.hide()
            end
          end
          @txt.show_position(loc)
          @txt.set_selection(loc, loc + findstring.length())
        else # Scintilla
          # FIXME: Take into account search direction
          @txt.set_target_start(@txt.get_target_end)
          @txt.set_target_end(@txt.get_length - 1)
          # FIXME: get flags from find dialog
          @txt.set_search_flags(0)
          loc = @txt.search_in_target(event.get_find_string)
          if loc == -1
            dlg = Wx::MessageDialog.new(self, 'Find String Not Found', 'Find String Not Found in Demo File',
                                          Wx::OK | Wx::ICON_INFORMATION)
            dlg.show_modal()
            dlg.destroy()
          end

          if @finddlg
            if loc == -1
              @finddlg.set_focus()
              return
            end
          end
          @txt.ensure_caret_visible
          @txt.set_selection(loc, loc + event.get_find_string.length)
        end
    end
    
    def on_find_next(event)
        # FIXME: Saving an event is probably a bad idea
        if @finddata.get_find_string() != ""
            on_find(event)
        else
            on_help_find(event)
        end
    end
    
    def on_find_close(event)
        event.get_dialog().destroy()
    end
    
    def show_tip()
      tips_file = File.join(File.dirname(__FILE__), 'tips.txt')
      tp = Wx::create_file_tip_provider( tips_file, rand(6) )
      Wx::show_tip(self, tp)
    end
    
    def on_demo_menu(childItem)
        # Also, for some reason I haven't figured out yet either, the demo executes two times
        selectedDemo = @treeMap[childItem]
        if selectedDemo
            @tree.select_item(selectedDemo)
            @tree.ensure_visible(selectedDemo)
        end
    end
    
    def on_iconize(event)
        Wx::log_message("on_iconify")
        event.skip
    end
    
    def on_maximize(event)
        Wx::log_message("on_maximize")
        event.skip
    end

    # FIXME: Refactor into a class
    def setup_editor(parent)
      panel = Wx::Panel.new(parent)
      panel.hide
      sci = setup_scintilla(panel)
      @save_button = Wx::Button.new(panel, -1, 'Save Changes')
      @delete_button = Wx::Button.new(panel, -1, 'Delete Modified')
      @save_button.enable(false);
      panel.evt_button(@save_button.get_id) { on_save }
      panel.evt_button(@delete_button.get_id) { on_delete }
      panel.evt_sci_modified { on_modified }

      radio_buttons = {:original => Wx::RadioButton.new(panel, -1, "Original", Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE, Wx::RB_GROUP),
                       :modified => Wx::RadioButton.new(panel, -1, "Modified")}
      
      @control_box = Wx::BoxSizer.new(Wx::HORIZONTAL)
      @control_box.add(Wx::StaticText.new(panel, -1, 'Active Version:'), 0, Wx::RIGHT | Wx::LEFT | Wx::ALIGN_CENTER_VERTICAL, 5)
      radio_buttons.each_pair { |id, button|
        @control_box.add(button, 0, Wx::EXPAND | Wx::RIGHT, 5)
        evt_radiobutton(button.get_id) { |event| on_radio_button(event) }
      }
      @control_box.add(@save_button, 0, Wx::RIGHT, 5)
      @control_box.add(@delete_button, 0)

      @box = Wx::BoxSizer.new(Wx::VERTICAL)
      @box.add(@control_box, 0, Wx::EXPAND)
      @box.add(Wx::StaticLine.new(panel), 0, Wx::EXPAND)
      
      @box.add(sci, 1, Wx::EXPAND)
      @box.fit(panel)
      panel.set_sizer(@box)
      [panel, sci]
    end

    def setup_scintilla(parent)
      sci = Wx::Scintilla.new(parent)
      font = Wx::Font.new(10, Wx::TELETYPE, Wx::NORMAL, Wx::NORMAL)
      sci.style_set_font(Wx::SCI_STYLE_DEFAULT, font);
      sci.set_edge_mode(Wx::SCI_EDGE_LINE)
      line_num_margin = sci.text_width(Wx::SCI_STYLE_LINENUMBER, "_99999")
      sci.set_margin_width(0, line_num_margin)

      sci.style_set_foreground(Wx::SCI_STYLE_DEFAULT, Wx::BLACK);
      sci.style_set_background(Wx::SCI_STYLE_DEFAULT, Wx::WHITE);
      sci.style_set_foreground(Wx::SCI_STYLE_LINENUMBER, Wx::LIGHT_GREY);
      sci.style_set_background(Wx::SCI_STYLE_LINENUMBER, Wx::WHITE);
      sci.style_set_foreground(Wx::SCI_STYLE_INDENTGUIDE, Wx::LIGHT_GREY);

      sci.set_tab_width(2)
      sci.set_use_tabs(false)
      sci.set_tab_indents(true)
      sci.set_back_space_un_indents(true)
      sci.set_indent(2)
      sci.set_edge_column(80)

      sci.set_lexer(Wx::SCI_LEX_RUBY)
      sci.style_clear_all
      sci.style_set_foreground(2, Wx::RED)
      sci.style_set_foreground(3, Wx::GREEN)
      sci.style_set_foreground(5, Wx::BLUE)
      sci.style_set_foreground(6, Wx::BLUE)
      sci.style_set_foreground(7, Wx::BLUE)
      sci.set_key_words(0, "begin break elsif module retry unless end case next return until class ensure nil self when def false not super while alias defined? for or then yield and do if redo true else in rescue undef")

      sci.set_property("fold","1")
      sci.set_property("fold.compact", "0")
      sci.set_property("fold.comment", "1")
      sci.set_property("fold.preprocessor", "1")

      sci.set_margin_width(1, 0)
      sci.set_margin_type(1, Wx::SCI_MARGIN_SYMBOL)
      sci.set_margin_mask(1, Wx::SCI_MASK_FOLDERS)
      sci.set_margin_width(1, 20)

      sci.marker_define(Wx::SCI_MARKNUM_FOLDER, Wx::SCI_MARK_PLUS)
      sci.marker_define(Wx::SCI_MARKNUM_FOLDEROPEN, Wx::SCI_MARK_MINUS)
      sci.marker_define(Wx::SCI_MARKNUM_FOLDEREND, Wx::SCI_MARK_EMPTY)
      sci.marker_define(Wx::SCI_MARKNUM_FOLDERMIDTAIL, Wx::SCI_MARK_EMPTY)
      sci.marker_define(Wx::SCI_MARKNUM_FOLDEROPENMID, Wx::SCI_MARK_EMPTY)
      sci.marker_define(Wx::SCI_MARKNUM_FOLDERSUB, Wx::SCI_MARK_EMPTY)
      sci.marker_define(Wx::SCI_MARKNUM_FOLDERTAIL, Wx::SCI_MARK_EMPTY)
      sci.set_fold_flags(16)

      sci.set_margin_sensitive(1,1)
      sci
    end

    def on_save
      if not FileTest.directory?(File.dirname(modified_filename))
        if not Dir.mkdir(File.dirname(modified_filename))
          Wx::log_message("Unable to create directory 'modified'")
          return
        end
      end
      File.open(modified_filename, "w") { |file|
        file.write(@txt.get_text)
      }
      # FIXME: Reload module we just saved
    end

    def on_delete
      if File.exists?(modified_filename)
        File.unlink(modified_filename)
      end
      # FIXME: Update state
    end

    def on_modified
      @save_button.enable(@txt.get_modify)
    end

    def on_radio_button(event)
      # FIXME: Can't do anything here yet
    end

    def modified_filename
      File.join(File.dirname(@filename), "modified", File.basename(@filename))
    end
end

class DemoTaskBarIcon < Wx::TaskBarIcon
  # TODO: Need a new_id function like wxPython has
  TBMENU_RESTORE = 6000
  TBMENU_CLOSE = 6001
  TBMENU_CHANGE = 6002
  TBMENU_REMOVE = 6003

  def initialize(frame)
    super()

    @frame = frame

    # starting image
    icon = make_icon('wxruby-128x128.png')
    set_icon(icon, 'wxRuby Demo')
    @image_index = 1

    # events
    evt_taskbar_left_dclick  {|evt| on_taskbar_activate(evt) }
    
    evt_menu(TBMENU_RESTORE) {|evt| on_taskbar_activate(evt) }
    evt_menu(TBMENU_CLOSE)   { @frame.close }
    evt_menu(TBMENU_CHANGE)  {|evt| on_taskbar_change(evt) }
    evt_menu(TBMENU_REMOVE)  { remove_icon }
  end

  def create_popup_menu
    # Called by the base class when it needs to popup the menu
    #  (the default evt_right_down event).  Create and return
    #  the menu to display.
    menu = Wx::Menu.new
    menu.append(TBMENU_RESTORE, "Restore wxRuby Demo")
    menu.append(TBMENU_CLOSE,   "Close wxRuby Demo")
    menu.append_separator
    menu.append(TBMENU_CHANGE,  "Change the TB Icon")
    menu.append(TBMENU_REMOVE,  "Remove the TB Icon")
    return menu
  end

  def make_icon(imgname)
    # Different platforms have different requirements for the
    #  taskbar icon size
    filename = File.join( File.dirname(__FILE__), 'icons', imgname )
    img = Wx::Image.new(filename)
    if Wx::PLATFORM == "WXMSW"
      img = img.scale(16, 16)
    elsif Wx::PLATFORM == "WXGTK"
      img = img.scale(22, 22)
    end
    # WXMAC can be any size up to 128x128, so don't scale
    icon = Wx::Icon.new
    icon.copy_from_bitmap(Wx::Bitmap.new(img))
    return icon
  end

  def on_taskbar_activate(evt)
    if @frame.is_iconized
      @frame.iconize(false)
    end
    if not @frame.is_shown
      @frame.show(true)
    end
    @frame.raise
  end

  def on_taskbar_change(evt)
    names = [ "wxruby-128x128.png", "wxwin16x16.xpm", "smiles.xpm", "mondrian.xpm" ]
    name = names[@image_index]
    @image_index += 1
    if @image_index >= names.length
      @image_index = 0
    end

    icon = make_icon(name)
    set_icon(icon, 'This is a new icon: ' + name)
  end

end

class DemoApp < Wx::App
  def on_init
    frame = WxRubyDemo.new("WxRuby BIG combined demo",
                           Wx::DEFAULT_POSITION, 
                           Wx::Size.new(750, 550))

    frame.show(true)
  end
end

demo = DemoApp.new
demo.main_loop
