Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
debreate / usr / share / debreate / dbr / textinput.py
Size: Mime:
# -*- coding: utf-8 -*-

## \package dbr.textinput

# MIT licensing
# See: docs/LICENSE.txt


import time, wx

from dbr.font               import MONOSPACED_LG
from dbr.language           import GT
from dbr.panel              import BorderedPanel
from globals.fileio         import ReadFile
from globals.strings        import TextIsEmpty
from globals.wizardhelper   import GetTopWindow


## Text control set up for handling file drop events
class TextArea(wx.TextCtrl):
    def __init__(self, parent, ID=wx.ID_ANY, value=wx.EmptyString, pos=wx.DefaultPosition,
            size=wx.DefaultSize, style=0, validator=wx.DefaultValidator, name=wx.TextCtrlNameStr):
        wx.TextCtrl.__init__(self, parent, ID, value, pos, size, style, validator, name)
        
        # Enable to override default behavior of adding filename string
        self.DragAcceptFiles(True)
        
        self.accepts_drop = False
        
        # *** Event handlers *** #
        
        self.Bind(wx.EVT_DROP_FILES, self.OnDropFiles)
    
    
    ## Allow dropping files from file manager
    def EnableDropTarget(self, enable=True):
        self.accepts_drop = enable
    
    
    ## TODO: Doxygen
    def IsDropTarget(self):
        return self.accepts_drop
    
    
    ## TODO: Doxygen
    def OnDropFiles(self, event=None):
        if not self.IsEnabled() or not event:
            return False
        
        # Flash red if doesn't accept file drops
        if not self.IsDropTarget():
            parent = self.GetParent()
            
            if isinstance(parent, TextAreaPanel):
                main_object = parent
            
            else:
                main_object = self
            
            bgcolor = main_object.GetBackgroundColour()
            main_object.SetBackgroundColour(wx.RED)
            
            wx.Yield()
            time.sleep(0.1)
            
            main_object.SetBackgroundColour(bgcolor)
            
            return False
        
        filename = event.GetFiles()
        
        if not filename:
            return False
        
        # Use only the first file
        if isinstance(filename, (tuple, list)):
            filename = filename[0]
        
        if not TextIsEmpty(self.GetValue()):
            msg_li1 = GT(u'This will delete all text')
            msg_li2 = GT(u'Continue?')
            
            # FIXME: Use custom dialogs (currently cannot import)
            message = wx.MessageDialog(GetTopWindow(), u'{}\n\n{}'.format(msg_li1, msg_li2),
                    GT(u'Warning'), wx.OK|wx.CANCEL|wx.ICON_WARNING)
            
            confirmed = message.ShowModal() in (wx.OK, wx.ID_OK, wx.YES, wx.ID_YES)
            
            if not confirmed:
                return False
        
        try:
            input_text = ReadFile(filename)
            
            if input_text:
                self.SetValue(input_text)
                
                return True
        
        except UnicodeDecodeError:
            pass
        
        #ShowErrorDialog(GT(u'There was an error reading file: {}').format(filename))
        wx.MessageDialog(GetTopWindow(), GT(u'There was an error reading file: {}').format(filename),
                GT(u'Error'), wx.OK|wx.ICON_ERROR).ShowModal()
        
        return False


## A text control that is multiline & uses a themed border
class TextAreaML(TextArea):
    def __init__(self, parent, ID=wx.ID_ANY, value=wx.EmptyString, pos=wx.DefaultPosition,
                size=wx.DefaultSize, style=0, validator=wx.DefaultValidator, name=wx.TextCtrlNameStr):
        TextArea.__init__(self, parent, ID, value, pos, size, style|wx.TE_MULTILINE, validator, name)
    
    
    ## Sets the font size of the text area
    #  
    #  \param point_size
    #        \b \e int : New point size of font
    def SetFontSize(self, point_size):
        font = self.GetFont()
        font.SetPointSize(point_size)
        
        self.SetFont(font)


## Somewhat of a hack to attemtp to get rounded corners on text control border
class TextAreaPanel(BorderedPanel):
    def __init__(self, parent, ID=wx.ID_ANY, value=wx.EmptyString, pos=wx.DefaultPosition,
                size=wx.DefaultSize, style=0, name=wx.TextCtrlNameStr):
        BorderedPanel.__init__(self, parent, ID, pos, size, name=name)
        
        self.textarea = TextAreaML(self, style=style|wx.BORDER_NONE)
        if not TextIsEmpty(value):
            self.textarea.SetValue(value)
        
        # For setting color of disabled panel
        self.clr_disabled = self.GetBackgroundColour()
        self.clr_enabled = self.textarea.GetBackgroundColour()
        
        # Match panel color to text control
        self.SetBackgroundColour(self.textarea.GetBackgroundColour())
        
        self.layout_V1 = wx.BoxSizer(wx.HORIZONTAL)
        self.layout_V1.Add(self.textarea, 1, wx.EXPAND|wx.ALL, 2)
        
        self.SetAutoLayout(True)
        self.SetSizer(self.layout_V1)
        self.Layout()
    
    
    ## Clears all text in the text area
    def Clear(self):
        self.textarea.Clear()
    
    
    ## Disables self & text area
    def Disable(self):
        return self.Enable(False)
    
    
    ## Disables or enables self & text area
    #  
    #  Because of issues with text control background color, it
    #  must be set manually when the parent TextAreaPanel
    #  is disabled. This causes some text artifacts in wx 3.0
    #  when using the SetValue & WriteText methods. Because of
    #  that, when the control is enabled/disabled, the value
    #  is stored, then the control cleared. When the new
    #  background color is set, the value is restored, causing
    #  the text to take on the same background color.
    def Enable(self, *args, **kwargs):
        # Clearing text area is done as workaround for text background color bug
        current_value = self.textarea.GetValue()
        insertion_point = self.textarea.GetInsertionPoint()
        self.textarea.Clear()
        
        return_value = BorderedPanel.Enable(self, *args, **kwargs)
        
        if self.IsEnabled():
            self.SetBackgroundColour(self.clr_enabled)
        
            # Older versions of wx do not change color of disabled multiline text control
            if wx.MAJOR_VERSION < 3:
                self.textarea.SetBackgroundColour(self.clr_enabled)
        
        else:
            self.SetBackgroundColour(self.clr_disabled)
        
            # Older versions of wx do not change color of disabled multiline text control
            if wx.MAJOR_VERSION < 3:
                self.textarea.SetBackgroundColour(self.clr_disabled)
        
        # Reinstate the text
        self.textarea.SetValue(current_value)
        self.textarea.SetInsertionPoint(insertion_point)
        
        return return_value
    
    
    ## Allow dropping files from file manager
    def EnableDropTarget(self, enable=True):
        return self.textarea.EnableDropTarget(enable)
    
    
    ## Retrieves the caret instance of the wx.TextCtrl
    def GetCaret(self):
        return self.textarea.GetCaret()
    
    
    ## Retrieves font that text area is using
    def GetFont(self):
        return self.textarea.GetFont()
    
    
    ## Retrieves carat position
    def GetInsertionPoint(self):
        return self.textarea.GetInsertionPoint()
    
    
    ## TODO: Doxygen
    def GetLastPosition(self):
        return self.textarea.GetLastPosition()
    
    
    ## Retrieves the text area object
    def GetTextCtrl(self):
        return self.textarea
    
    
    ## Retrieves text from text input
    def GetValue(self):
        return self.textarea.GetValue()
    
    
    ## Returns True if text area is empty
    def IsEmpty(self):
        return self.textarea.IsEmpty()
    
    
    ## TODO: Doxygen
    def SetBackgroundColour(self, *args, **kwargs):
        self.textarea.SetBackgroundColour(*args, **kwargs)
        return BorderedPanel.SetBackgroundColour(self, *args, **kwargs)
    
    
    ## Sets the caret instance for the wx.TextCtrl
    def SetCaret(self, caret):
        return self.textarea.SetCaret(caret)
    
    
    ## Sets font in text area
    def SetFont(self, font):
        self.textarea.SetFont(font)
    
    
    ## Sets the font size of the text in the text area
    #  
    #  \override dbr.textinput.MultilineTextCtrl.SetFontSize
    def SetFontSize(self, point_size):
        self.textarea.SetFontSize(point_size)
    
    
    ## TODO: Doxygen
    def SetForegroundColour(self, *args, **kwargs):
        self.textarea.SetForegroundColour(*args, **kwargs)
        return BorderedPanel.SetForegroundColour(self, *args, **kwargs)
    
    
    ## Places carat to position in text area
    def SetInsertionPoint(self, point):
        self.textarea.SetInsertionPoint(point)
    
    
    ## Places carat at end of text area
    def SetInsertionPointEnd(self):
        self.textarea.SetInsertionPointEnd()
    
    
    ## Sets text in text area
    def SetValue(self, text):
        self.textarea.SetValue(text)
    
    
    ## TODO: Doxygen
    def ShowPosition(self, pos):
        return self.textarea.ShowPosition(pos)
    
    
    ## Writes to the text area
    def WriteText(self, text):
        self.textarea.WriteText(text)


MT_NO_BTN = 0
MT_BTN_TL = 1
MT_BTN_TR = 2
MT_BTN_BL = 3
MT_BTN_BR = 4

button_H_pos = {
    MT_BTN_TL: wx.ALIGN_LEFT,
    MT_BTN_TR: wx.ALIGN_RIGHT,
    MT_BTN_BL: wx.ALIGN_LEFT,
    MT_BTN_BR: wx.ALIGN_RIGHT,
}


## TODO: Doxygen
#  
#  TODO: Remove button & toggle text from external buttons
class MonospaceTextArea(TextAreaPanel):
    def __init__(self, parent, ID=wx.ID_ANY, value=wx.EmptyString, button=MT_NO_BTN,
                pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TAB_TRAVERSAL,
                name=wx.TextCtrlNameStr):
        TextAreaPanel.__init__(self, parent, ID, value, pos, size, style, name)
        
        self.textarea.SetFont(MONOSPACED_LG)
        
        if button:
            btn_font = wx.Button(self, label=GT(u'Text Size'))
            if button in (MT_BTN_TL, MT_BTN_TR):
                self.layout_V1.Insert(0, btn_font, 0, button_H_pos[button]|wx.LEFT|wx.RIGHT, 5)
            
            else:
                self.layout_V1.Add(btn_font, 0, button_H_pos[button]|wx.LEFT|wx.RIGHT, 5)
            
            btn_font.Bind(wx.EVT_BUTTON, self.OnToggleTextSize)
    
    
    ## TODO: Doxygen
    def OnToggleTextSize(self, event=None):
        # Save insertion point
        insertion = self.textarea.GetInsertionPoint()
        
        sizes = {
            7: 8,
            8: 10,
            10: 11,
            11: 7,
        }
        
        font = self.textarea.GetFont()
        new_size = sizes[font.GetPointSize()]
        font.SetPointSize(new_size)
        
        self.textarea.SetFont(font)
        self.textarea.SetInsertionPoint(insertion)
        self.textarea.SetFocus()