import sys, wx, wx.stc

class FullscreenEditFrame(wx.Frame):
   """
   This opens a modal fullscreen editor with some text. When the user's done,
   this calls the callback function passed to the constructor with the new text.

   A lot of the stuff dealing with wx.stc.StyledTextCtrl comes from:
   http://www.psychicorigami.com/2009/01/05/a-5k-python-fullscreen-text-editor/
   """

   def __init__(self, parent, app, frame = None, title = '', initialText = '', callback = lambda i: i):
       wx.Frame.__init__(self, parent, wx.ID_ANY, title = title, size = (400, 400))
       self.app = app
       self.callback = callback
       self.frame = frame
       self.cursorVisible = True

       # menu bar
       # this is never seen by the user,
       # but lets them hit ctrl-S to save

       menuBar = wx.MenuBar()
       menu = wx.Menu()
       menu.Append(wx.ID_SAVE, '&Save Story\tCtrl-S')
       self.Bind(wx.EVT_MENU, lambda e: self.frame.widget.parent.parent.save, id = wx.ID_SAVE)
       menuBar.Append(menu, 'Commands')
       self.SetMenuBar(menuBar)

       # margins

       self.marginPanel = wx.Panel(self)
       marginSizer = wx.BoxSizer(wx.VERTICAL)  # doesn't really matter
       self.marginPanel.SetSizer(marginSizer)

       # content

       self.panel = wx.Panel(self.marginPanel)
       sizer = wx.BoxSizer(wx.VERTICAL)
       marginSizer.Add(self.panel, 1, flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 100)

       # controls

       self.editCtrl = wx.stc.StyledTextCtrl(self.panel, style = wx.NO_BORDER | wx.TE_NO_VSCROLL | \
                                             wx.TE_MULTILINE | wx.TE_PROCESS_TAB)
       self.editCtrl.SetMargins(0, 0)
       self.editCtrl.SetMarginWidth(1, 0)
       self.editCtrl.SetWrapMode(wx.stc.STC_WRAP_WORD)
       self.editCtrl.SetText(initialText)
       self.editCtrl.SetUseHorizontalScrollBar(False)
       self.editCtrl.SetUseVerticalScrollBar(False)
       self.editCtrl.SetCaretPeriod(750)

       self.directions = wx.StaticText(self.panel, label = FullscreenEditFrame.DIRECTIONS, style = wx.ALIGN_CENTRE)
       labelFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
       labelFont.SetPointSize(FullscreenEditFrame.LABEL_FONT_SIZE)
       self.directions.SetFont(labelFont)

       self.applyPrefs()
       sizer.Add(self.editCtrl, 1, flag = wx.EXPAND | wx.ALL)
       sizer.Add(self.directions, 0, flag = wx.TOP | wx.BOTTOM, border = 6)
       self.panel.SetSizer(sizer)

       # events

       self.Bind(wx.EVT_KEY_DOWN, self.keyListener)
       self.Bind(wx.EVT_MOTION, self.showCursor)
       self.editCtrl.Bind(wx.EVT_KEY_DOWN, self.keyListener)
       self.editCtrl.Bind(wx.EVT_MOTION, self.showCursor)

       self.editCtrl.SetFocus()
       self.editCtrl.SetSelection(-1, -1)
       self.SetIcon(self.app.icon)
       self.Show(True)
       self.ShowFullScreen(True)

   def close(self):
       self.callback(self.editCtrl.GetText())
       if sys.platform == 'darwin': self.ShowFullScreen(False)
       self.Close()

   def applyPrefs(self):
       """
       Applies user preferences to this frame.
       """
       editFont = wx.Font(self.app.config.ReadInt('fsFontSize'), wx.FONTFAMILY_MODERN, \
                          wx.FONTSTYLE_NORMAL, wx.NORMAL, False, self.app.config.Read('fsFontFace'))
       bgColor = self.app.config.Read('fsBgColor')
       textColor = self.app.config.Read('fsTextColor')
       lineHeight = self.app.config.ReadInt('fslineHeight') / float(100)

       self.panel.SetBackgroundColour(bgColor)
       self.marginPanel.SetBackgroundColour(bgColor)

       self.editCtrl.SetBackgroundColour(bgColor)
       self.editCtrl.SetForegroundColour(textColor)
       self.editCtrl.StyleSetBackground(wx.stc.STC_STYLE_DEFAULT, bgColor)
       self.editCtrl.SetCaretForeground(textColor)
       self.editCtrl.SetSelBackground(True, textColor)
       self.editCtrl.SetSelForeground(True, bgColor)

       defaultStyle = self.editCtrl.GetStyleAt(0)
       self.editCtrl.StyleSetForeground(defaultStyle, textColor)
       self.editCtrl.StyleSetBackground(defaultStyle, bgColor)
       self.editCtrl.StyleSetFont(defaultStyle, editFont)

       # we stuff a larger font into a style def we never use
       # to force line spacing

       editFont.SetPointSize(editFont.GetPointSize() * lineHeight)
       self.editCtrl.StyleSetFont(wx.stc.STC_STYLE_BRACELIGHT, editFont)

       self.directions.SetForegroundColour(textColor)

   def keyListener(self, event):
       """
       Listens for a key that indicates this frame should close; otherwise lets the event propagate.
       This also hides the mouse cursor; the showCursor method, bound to the mouse motion event,
       restores it when the user moves it.
       """
       key = event.GetKeyCode()

       if key == wx.WXK_F12:
           self.close()

       if key == wx.WXK_ESCAPE:
           self.close()
           self.frame.Destroy()

       self.hideCursor()
       event.Skip()

   def hideCursor(self, event = None):
       if self.cursorVisible:
           self.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
           self.editCtrl.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
           self.cursorVisible = False

   def showCursor(self, event = None):
       if not self.cursorVisible:
           self.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
           self.editCtrl.SetCursor(wx.StockCursor(wx.CURSOR_IBEAM))
           self.cursorVisible = True

   DIRECTIONS = 'Press Escape to close this passage, F12 to leave fullscreen.'
   LABEL_FONT_SIZE = 10