# GNU Enterprise Forms - wx 2.6 UI Driver - Entry widgets
#
# Copyright 2001-2009 Free Software Foundation
#
# This file is part of GNU Enterprise
#
# GNU Enterprise is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 3, or (at your option) any later version.
#
# GNU Enterprise is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with program; see the file COPYING. If not,
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
# $Id: entry.py 10012 2009-10-27 16:00:31Z reinhard $
"""
Implementation of the <entry> tag
"""

import os
import wx

from gnue.forms.uidrivers.wx26.widgets import _base
from gnue.forms.input import GFKeyMapper
from gnue.forms.input.GFKeyMapper import vk

__all__ = ['UIEntry']

# =============================================================================
# Interface class for entry widgets
# =============================================================================

class UIEntry (_base.UIHelper):
    """
    Interface implementation for entry widgets.
    """

    # -------------------------------------------------------------------------
    # Create the real wx widget
    # -------------------------------------------------------------------------

    def _create_widget_ (self, event, spacer):
        """
        Create the wx widget. The actual creation will be dispatched to a
        method called '__build_<style>' depending on the object's style.
        """

        owner = self.getParent()

        if self.in_grid:
            parent = owner._get_cell(self, spacer)
        else:
            parent = event.container

        style = self._gfObject.style.lower()
        func = getattr(self, "_UIEntry__build_%s" % style)
        self.__border = 0
        (self.label, self.widget) = func(parent)

        owner.add_widgets(self, spacer, self.__border)

        if self.in_grid:
            self.widget._gnue_label_ = self.label

        self.__current_row = None
        self.__current_row_color_save = None

        # We return the entry object here, since we will bind events to it
        # later
        return self.widget


    # -------------------------------------------------------------------------
    # Widget construction methods
    # -------------------------------------------------------------------------

    def __build_default(self, parent, password=False, multiline=False):

        xFlags = wx.TE_PROCESS_TAB

        if password:
            xFlags |= wx.TE_PASSWORD

        if multiline:
            xFlags |= wx.TE_MULTILINE
        else:
            xFlags |= wx.TE_PROCESS_ENTER

        # Right-align numeric fields.  This does work on wxMSW and wxGTK only.
        if self._gfObject._field.datatype == 'number':
            xFlags |= wx.TE_RIGHT

        csize = self.get_default_size()

        # NOTE: a multiline text control has a native size which is about 60
        # pixels.  This height might be bigger than for example two grid cells.
        # In that case those lines in the GridBagSizer would be stretched which
        # is not what we want!  To avoid that, we set the size of the control
        # to 1 pixel in height, which will be overriden by the containing
        # GridBagSizer when it comes to layout.  These restrictions are needed
        # for positioned layout only
        if multiline and not self.managed:
            csize = (csize[0], 1)
            self.__border = self._uiDriver.control_border('default')

        ctrl = wx.TextCtrl(parent, -1, size=csize, style=xFlags)
        ctrl.Bind(wx.EVT_TEXT, self.__on_text_changed)
        ctrl.Bind(wx.EVT_CHAR, self.__on_keypress)
        ctrl.Bind(wx.EVT_KEY_DOWN, self.__on_key_down)
        ctrl.Bind(wx.EVT_SET_FOCUS, self.__on_set_focus)

        return [self.__add_entry_label(parent), ctrl]

    # -------------------------------------------------------------------------

    def __build_password(self, parent):

        return self.__build_default(parent, True)

    # -------------------------------------------------------------------------

    def __build_multiline(self, parent):

        return self.__build_default(parent, multiline=True)

    # -------------------------------------------------------------------------

    def __build_label(self, parent):

        ctrl = wx.StaticText(parent, -1, "")
        return [self.__add_entry_label(parent), ctrl]

    # -------------------------------------------------------------------------

    def __build_checkbox (self, parent):

        result = wx.CheckBox (parent, -1, self._gfObject.label or '',
                style=wx.CHK_3STATE)
        result.Bind (wx.EVT_CHECKBOX, self.__on_toggle_checkbox)
        result.Bind (wx.EVT_CHAR, self.__on_keypress)
        result.Bind (wx.EVT_KEY_DOWN, self.__on_key_down)
        result.Bind (wx.EVT_SET_FOCUS, self.__on_set_focus)

        label = None

        return [label, result]

    # -------------------------------------------------------------------------

    def __build_dropdown(self, parent):

        csize = self.get_default_size()
        result = wx.ComboBox(parent, -1, size=csize, style=wx.CB_DROPDOWN |
                wx.TE_PROCESS_TAB | wx.TE_PROCESS_ENTER)

        # On wxMac a Combobox is a container holding a TextCtrl and a Choice.
        # We have to bind the Focus- and Char-Events to the TextCtrl widget.
        if 'wxMac' in wx.PlatformInfo:
            for child in result.GetChildren():
                if isinstance(child, wx.TextCtrl):
                    item = result._entry = child
                elif isinstance(child, wx.Choice):
                    child.Bind(wx.EVT_LEFT_DOWN, self.__on_mac_choice_clicked)
        else:
            item = result

        if 'wxGTK' in wx.PlatformInfo:
            result.Bind(wx.EVT_TEXT, self.__on_gtk_text_changed)
        else:
            result.Bind(wx.EVT_TEXT, self.__on_text_changed)

        item.Bind(wx.EVT_SET_FOCUS, self.__on_set_focus)
        item.Bind(wx.EVT_KEY_DOWN, self.__on_combo_keydown)

        # Workaround for a bug in wxGTK 2.8 (tested with 2.8.7.1) - ComboBox
        # does not receive EVT_SET_FOCUS when the dropdown button is clicked.
        if 'wxGTK' in wx.PlatformInfo:
            item.Bind(wx.EVT_COMBOBOX, self.__on_combobox)

        if 'wxMSW' in wx.PlatformInfo:
            item.Bind(wx.EVT_MOUSEWHEEL, self.__on_cbx_wheel)

        return [self.__add_entry_label(parent), result]

    # -------------------------------------------------------------------------

    def __build_listbox(self, parent):

        # NOTE: please have a look at the note on multiline text edits above
        if not self.managed:
            csize = (self.get_default_size()[0], 1)
        else:
            csize = (self.get_default_size()[0], -1)
        self.__border = self._uiDriver.control_border('default')

        result = wx.ListBox(parent, -1, size=csize, style=wx.LB_SINGLE)

        result.Bind(wx.EVT_LISTBOX, self.__on_item_selected)
        result.Bind(wx.EVT_KEY_DOWN, self.__on_key_down)
        result.Bind(wx.EVT_SET_FOCUS, self.__on_set_focus)

        return [self.__add_entry_label(parent), result]

    # -------------------------------------------------------------------------

    def __add_entry_label(self, parent):

        if self.in_grid:
            label = wx.StaticText(parent, -1)
            # Bind the LEFT_UP event to both, the panel and the label widget,
            # so clicking an empty cell works too
            parent.Bind(wx.EVT_LEFT_UP, self.__on_label_click)
            label.Bind(wx.EVT_LEFT_UP, self.__on_label_click)

        elif self._gfObject.label:
            # Replace blanks by non-breaking space to avoid random linebreaks
            # in labels (sometimes done by wx, probably due to rounding errors
            # in size calculations)
            text = self._gfObject.label.replace(u" ", u"\240")
            label = wx.StaticText(parent, -1, text)
        else:
            label = None

        return label


    # -------------------------------------------------------------------------
    # Event handlers
    # -------------------------------------------------------------------------

    def __on_label_click(self, event):

        label = event.GetEventObject()
        for item in self.widgets:
            if isinstance(label, wx.Panel):
                # An empty cell has been clicked
                other = item.GetParent()
            else:
                other = item._gnue_label_

            if other == label:
                if item.IsEnabled() and self._gfObject.style.lower() != 'label':
                    # The UI focus is not on the entry yet (actually it's not
                    # even visible yet), so we have to move the focus on both
                    # the UI and GF level.
                    self._gfObject.set_focus(self.widgets.index(item))
                else:
                    # This entry is not focusable, so we at least move the
                    # database cursor to the record behind this entry.
                    self._gfObject._event_jump_records(
                            self.widgets.index(item))
                return

        event.Skip()

    # -------------------------------------------------------------------------

    def __on_set_focus(self, event):

        # FIXME: workaround for issue-141:  If not the first page of a notebook
        # control is shown and one closes the form, an EVT_SET_FOCUS event is
        # generated for widgets on the prior pages.  At this time the main
        # window is already destroyed and so it leads to a segmentation fault.
        # To avoid it, we exit here if the main window is already destroyed
        if self._uiForm.main_window is None:
            return

        # This event is blocked while changing a page - the GF moves the focus
        # to where it wants to have it anyway.
        if self._uiForm.block_focus_events:
            return

        # Let the GF focus follow
        lookup = event.GetEventObject()
        if 'wxMac' in wx.PlatformInfo and self._gfObject.style == 'dropdown':
            lookup = lookup.GetParent()
        self._gfObject._event_set_focus(self.widgets.index(lookup))
        event.Skip()

    # -------------------------------------------------------------------------

    def __on_mac_choice_clicked(self, event):

        lookup = event.GetEventObject().GetParent()
        lookup._entry.SetFocus()
        self._gfObject._event_set_focus(self.widgets.index(lookup))
        event.Skip()


    # -------------------------------------------------------------------------

    def __on_toggle_checkbox(self, event):

        self._request('TOGGLECHKBOX')

    # -------------------------------------------------------------------------

    def __on_item_selected(self, event):

        self._request('REPLACEVALUE', index=event.GetSelection(),
                text=event.GetString())

    # -------------------------------------------------------------------------

    def __on_text_changed(self, event):

        widget = event.GetEventObject()
        cursor = widget.GetInsertionPoint()

        self._request('REPLACEVALUE', text=widget.GetValue(), position=cursor)

    # -------------------------------------------------------------------------

    def __on_gtk_text_changed(self, event):

        # FIXME: workaround for issue-144.  Setting a selection within an
        # EVT_TEXT event does not work on wx.GTK, so we defer the replace-event
        # to the next idle loop.
        # We do not pass the position here because it's not correct - the
        # cursor position is not yet updated at the time this is called. So we
        # let the GF* logic figure out the new cursor position.
        wx.CallAfter(self._request, 'REPLACEVALUE', text=event.GetString())

        event.Skip()


    # -------------------------------------------------------------------------

    def __on_key_down(self, event):

        # FIXME: Until a button can be flagged as 'Cancel'-Button, which closes
        # a dialog after the user pressed the escape key, we have to 'simulate'
        # that behaviour here.  This event handler can be removed, as soon as
        # such a button is available.  This event cannot be integrated into
        # EVT_CHAR since wxMSW does not generate such an event for WXK_ESCAPE.
        keycode = event.GetKeyCode()

        if isinstance(self._uiForm.main_window, wx.Dialog) and \
                keycode == wx.WXK_ESCAPE:
            self._uiForm.main_window.Close()
        else:
            event.Skip()


    # -------------------------------------------------------------------------

    def __on_combobox(self, event):

        # Workaround for a bug in wxGTK 2.8 (tested with 2.8.7.1) - ComboBox
        # does not receive EVT_SET_FOCUS when the dropdown button is clicked.
        combobox = event.GetEventObject()
        combobox.SetFocus()
        wx.CallAfter(combobox.SetMark, 0, -1)
        event.Skip()


    # -------------------------------------------------------------------------

    def __on_keypress(self, event):

        keycode = event.GetKeyCode()
        control = event.GetEventObject()

        # Treat enter of the numeric keypad the same way as normal enter key
        if keycode == wx.WXK_NUMPAD_ENTER:
            keycode = wx.WXK_RETURN

        # Let multiline entries handle return/up/down/pgup/pgdown themselves.
        if isinstance(control, wx.TextCtrl) and control.IsMultiLine():
            if keycode in (wx.WXK_RETURN, wx.WXK_UP, wx.WXK_DOWN,
                    wx.WXK_PAGEUP, wx.WXK_PAGEDOWN):
                event.Skip()
                return

        # Handle cursor up/down and page up/down.
        if not (event.ShiftDown() or event.CmdDown() or event.AltDown()):
            if keycode == wx.WXK_UP:
                self._gfObject._event_line_up()
            elif keycode == wx.WXK_DOWN:
                self._gfObject._event_line_down()
            elif keycode == wx.WXK_PAGEUP:
                self._gfObject._event_page_up()
            elif keycode == wx.WXK_PAGEDOWN:
                self._gfObject._event_page_down()

        command = None

        if keycode in [wx.WXK_TAB, wx.WXK_RETURN]:
            (command, args) = GFKeyMapper.KeyMapper.getEvent(keycode,
                  event.ShiftDown(),
                  event.CmdDown(),
                  event.AltDown())

        if command:
            if command == 'NEWLINE':
                self._request('KEYPRESS', text='\n')
            else:
                self._request(command, triggerName=args)
        else:
            event.Skip()


    # -------------------------------------------------------------------------

    def __on_combo_keydown(self, event):

        keycode = event.GetKeyCode()
        command = None

        # FIXME: Until a button can be flagged as 'Cancel'-Button, which closes
        # a dialog after the user pressed the escape key, we have to 'simulate'
        # that behaviour here.
        if isinstance(self._uiForm.main_window, wx.Dialog) and \
                keycode == wx.WXK_ESCAPE:
            self._uiForm.main_window.Close()
            return

        # Treat enter of the numeric keypad the same way as normal enter key
        if keycode == wx.WXK_NUMPAD_ENTER:
            keycode = wx.WXK_RETURN

        allowed = [wx.WXK_RETURN, wx.WXK_TAB]

        if keycode in allowed:
            (command, args) = GFKeyMapper.KeyMapper.getEvent (keycode,
                    event.ShiftDown(),
                    event.CmdDown(),
                    event.AltDown())

        if command:
            self._request(command, triggerName=args)
        else:
            event.Skip()
        
    # -------------------------------------------------------------------------

    def __on_cbx_wheel(self, event):

        # On wx.MSW we stop the propagation of a mouse wheel event here, to
        # prevent it from changing options in dropdowns
        event.StopPropagation()


    # -------------------------------------------------------------------------
    # Enable/disable this entry
    # -------------------------------------------------------------------------

    def _ui_enable_(self, index):
        self.widgets[index].Enable(True)

    # -------------------------------------------------------------------------

    def _ui_disable_(self, index):
        self.widgets[index].Enable(False)


    # -------------------------------------------------------------------------
    # Set "editable" status for this widget
    # -------------------------------------------------------------------------

    def _ui_set_editable_(self, index, editable):

        # Simple text controls can be explicitly set to non-editable, so they
        # don't accept keyboard input.
        if isinstance(self.widgets[index], wx.TextCtrl):
            self.widgets[index].SetEditable(editable)

        can_change = not 'wxMac' in wx.PlatformInfo
        if 'wxMSW' in wx.PlatformInfo:
            can_change = not isinstance(self.widgets[index], wx.ComboBox)

        # We set the background color to grey for all kinds of widgets if they
        # are not editable, so the user can see some difference.
        if can_change:
            if editable:
                colour = wx.NullColour
            else:
                colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)

            self.widgets[index].SetBackgroundColour(colour)
            self.widgets[index].Refresh()


    # -------------------------------------------------------------------------
    # Set the value of a widget
    # -------------------------------------------------------------------------

    def _ui_set_value_(self, index, value):
        """
        This function sets the value of a widget and optionally enables or
        disables the widget.
        """

        widget = self.widgets[index]

        if not widget:
            return

        widget.SetEvtHandlerEnabled(False)

        try:
            if isinstance(widget, wx.StaticText):
                widget.SetLabel(value)

            elif isinstance(widget, wx.ListBox):
                # TODO: We must allow setting the value to None, too, to be
                # able to move the cursor to the empty position at the start.
                # Must be tested under windows and Mac OS X.
                #
                # On wxMSW SetStringSelection() does not work properly with
                # empty values.
                index = widget.FindString(value)
                if index == -1:
                    widget.SetSelection(wx.NOT_FOUND)
                else:
                    widget.SetSelection(index)

            elif isinstance(widget, wx.CheckBox):
                if value is None:
                    widget.Set3StateValue(wx.CHK_UNDETERMINED)
                elif value:
                    widget.Set3StateValue(wx.CHK_CHECKED)
                else:
                    widget.Set3StateValue(wx.CHK_UNCHECKED)

            elif isinstance(widget, wx.ComboBox):
                # We use SetStringSelection to keep the selected index in sync
                # with the string value (e.g. in Choice-Controls on OS X)
                if not widget.SetStringSelection(value):
                    widget.SetValue(value)
            else:
                widget.SetValue(value)

        finally:
            if self.in_grid and widget._gnue_label_:
                if isinstance(widget._gnue_label_, wx.StaticText):
                    # Replace blanks by non-breaking space to avoid random
                    # linebreaks in labels (sometimes done by wx, probably due
                    # to rounding errors in size calculations)
                    text = ("%s" % value).replace(u" ", u"\240")
                    widget._gnue_label_.SetLabel(text)
                else:
                    widget._gnue_label_.SetValue(value)

            widget.SetEvtHandlerEnabled(True)
            widget.Refresh()


    # ------------------------------------------------------------------------
    # Set the cursor's location in a widget
    # ------------------------------------------------------------------------

    def _ui_set_cursor_position_(self, index, position):
        """
        Set the cursor position to the given location inside a capable widget.

        @param position: new position of the insertion point
        @param index: index of the widget to be changed (if rows > 0)
        """

        widget = self.widgets[index]

        if isinstance (widget, wx.ComboBox):
            widget.SetMark(position, position)

        elif hasattr (widget, 'SetInsertionPoint'):
            widget.SetInsertionPoint(position)


    # ------------------------------------------------------------------------
    # Set the selection inside a widget
    # ------------------------------------------------------------------------

    def _ui_set_selected_area_(self, index, selection1, selection2):
        """
        Sets the selection start/end inside a capable widget.

        @param selection1: start position of the selection
        @param selection2: end position of the selection
        @param index: index of the widget to be changed
        """
    
        widget = self.widgets[index]

        if isinstance(widget, wx.ComboBox):
            widget.SetMark(selection1, selection2)

        elif hasattr(widget, 'SetSelection'):
            if 'wxGTK' in wx.PlatformInfo:
                wx.CallAfter(widget.SetSelection, selection1, selection2)
            else:
                # Workaround for wxMSW: if a multiline text entry has more than
                # on line of text, SetSelection() does not work properly.
                if 'wxMSW' in wx.PlatformInfo and selection1 == 0:
                    if hasattr(widget, 'GetValue'):
                        val = widget.GetValue()
                        if len(val) == selection2:
                            selection1 = selection2 = -1

                widget.SetSelection(selection1, selection2)


    # -------------------------------------------------------------------------
    # Clipboard and selection
    # -------------------------------------------------------------------------

    def _ui_cut_(self, index):

        widget = self.widgets[index]

        if hasattr(widget, 'Cut'):
            widget.Cut()

    # -------------------------------------------------------------------------

    def _ui_copy_(self, index):

        widget = self.widgets[index]

        if hasattr(widget, 'Copy'):
            widget.Copy()

    # -------------------------------------------------------------------------

    def _ui_paste_(self, index):

        widget = self.widgets[index]

        if hasattr(widget, 'Paste'):
            widget.Paste()

    # -------------------------------------------------------------------------

    def _ui_select_all_(self, index):

        widget = self.widgets[index]

        if hasattr(widget, 'SetMark'):
            widget.SetMark(0, len(widget.GetValue()))

        elif hasattr(widget, 'SetSelection'):
            widget.SetSelection(-1, -1)


    # -------------------------------------------------------------------------
    # Mark the current row for label style entries
    # -------------------------------------------------------------------------

    def _ui_set_current_row_(self, index):
        
        # If we are a label in a grid, change the background color.
        if self.in_grid and self._gfObject.style.lower() == 'label':
            # Reset old current row to normal color.
            if self.__current_row is not None:
                widget = self.widgets[self.__current_row]
                widget.SetForegroundColour(wx.NullColour)
                widget._gnue_label_.SetForegroundColour(wx.NullColour)
                widget.GetParent().SetBackgroundColour(
                        self.__current_row_color_save)

            # Set new current row to specific color.
            if index == -1:
                self.__current_row = None
                self.__current_row_color_save = None
            else:
                self.__current_row = index
                widget = self.widgets[index]
                self.__current_row_color_save = \
                        widget.GetParent().GetBackgroundColour()
                widget.SetForegroundColour(
                    wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
                widget._gnue_label_.SetForegroundColour(
                    wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
                widget.GetParent().SetBackgroundColour(
                    wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))


    # -------------------------------------------------------------------------
    # Get the minimum size of a widget
    # -------------------------------------------------------------------------

    def get_minimum_size(self):
        """
        Return a wx.Size with the minimum size of a widget
        """

        # This is currently not used, because wx distributes the available
        # space based on the minimum size of the widgets instead of the "best"
        # or default size of the widgets. So we have to set the minimum size to
        # the same values as the default size.
        cellw = self._uiDriver.cellWidth
        cellh = self._uiDriver.cellHeight

        style = self._gfObject.style.lower()
        bw,bh = self._uiDriver.best_sizes.get(style, (-1, -1))

        minw = (self.min_width * cellw) or bw or -1
        minh = (self.min_height * cellh) or bh or -1

        return wx.Size(minw, minh)


    # -------------------------------------------------------------------------
    # Get the default size
    # -------------------------------------------------------------------------

    def get_default_size(self):
        """
        Return a wx.Size with the default (starting) size of a widget
        """
        cellw = self._uiDriver.cellWidth
        cellh = self._uiDriver.cellHeight

        if self.managed:
            style = self._gfObject.style.lower()
            if style == 'password':
                style = 'default'

            bw, bh = self._uiDriver.best_sizes.get(style, (-1, -1))

            deffield = self.get_field_length()
            # Do not exceed either the maximum allowed or 64 characters
            if (self.def_width or deffield) == 0:
                defw = bw
            else:
                if self.def_width:
                    defw = self.def_width * cellw
                else:
                    maxw = min(self.max_width or 32, 32)
                    defw = min(deffield, maxw) * cellw

            if not self.def_height:
                defh = -1
            else:
                maxh = max((self.max_height or 0) * cellh, bh)
                defh = min(max((self.def_height or 0) * cellh, bh), maxh)

            return wx.Size(defw, defh)
        else:
            # We're using the size of an empty GridCell instead of the average
            # character width.  It returns better looking forms.
            return wx.Size(cellw * self.chr_w, -1)


    # -------------------------------------------------------------------------
    # Get the maximum size
    # -------------------------------------------------------------------------

    def get_maximum_size(self):
        """
        Return a wx.Size with the maximum size of a widget
        """

        style = self._gfObject.style.lower()
        bw, bh = self._uiDriver.best_sizes.get(style, (-1, -1))
        cellw = self._uiDriver.cellWidth
        cellh = self._uiDriver.cellHeight

        length = self.get_field_length()
        if (self.max_width or length) == 0:
            maxw = -1
        else:
            maxw = ((self.max_width or length) * cellw) or bw

        if not self.max_height:
            maxh = -1
        else:
            maxh = ((self.max_height or 0) * cellh) or bh

        minw, minh = self.get_default_size().Get()
        if maxw != -1:
            maxw = max(maxw, minw)
        if maxh != -1:
            maxh = max(maxh, minh)
        return wx.Size(maxw, maxh)

    # -------------------------------------------------------------------------
    # Update the size hints of a widget
    # -------------------------------------------------------------------------

    def update_size_hints(self):

        if self.managed:
            minw, minh = self.get_default_size().Get()
            maxw, maxh = self.get_maximum_size().Get()

            for item in self.widgets:
                item.SetSizeHints(minw, minh, maxw, maxh)


    # -------------------------------------------------------------------------
    # Indicate whether this box is vertically growable
    # -------------------------------------------------------------------------

    def is_growable(self):

        return (self._gfObject.style.lower() in ['multiline', 'listbox'])


# =============================================================================
# Configuration
# =============================================================================

configuration = {
  'baseClass': UIEntry,
  'provides' : 'GFEntry',
  'container': 0
}

# Translate from wx keystrokes to our virtual keystrokes
wxKeyTranslations = {
    vk.C      : 3,                vk.V         : 22,
    vk.X      : 24,               vk.A         : 1,
    vk.F1     : wx.WXK_F1,        vk.F2        : wx.WXK_F2,
    vk.F3     : wx.WXK_F3,        vk.F4        : wx.WXK_F4,
    vk.F5     : wx.WXK_F5,        vk.F6        : wx.WXK_F6,
    vk.F7     : wx.WXK_F7,        vk.F8        : wx.WXK_F8,
    vk.F9     : wx.WXK_F9,        vk.F10       : wx.WXK_F10,
    vk.F11    : wx.WXK_F11,       vk.F12       : wx.WXK_F12,
    vk.INSERT : wx.WXK_INSERT,    vk.DELETE    : wx.WXK_DELETE,
    vk.HOME   : wx.WXK_HOME,      vk.END       : wx.WXK_END,
    vk.PAGEUP : wx.WXK_PRIOR,     vk.PAGEDOWN  : wx.WXK_NEXT,
    vk.UP     : wx.WXK_UP,        vk.DOWN      : wx.WXK_DOWN,
    vk.LEFT   : wx.WXK_LEFT,      vk.RIGHT     : wx.WXK_RIGHT,
    vk.TAB    : wx.WXK_TAB,
    vk.ENTER  : wx.WXK_RETURN,    vk.BACKSPACE : wx.WXK_BACK,
    vk.RETURN : wx.WXK_RETURN}

GFKeyMapper.KeyMapper.setUIKeyMap(wxKeyTranslations)
