Exemplo n.º 1
0
    def __init__(self, parent, widget, app):
        self.widget = widget
        self.app = app
        self.syncTimer = None
        self.lastFindRegexp = None
        self.lastFindFlags = None
        self.usingLexer = True

        wx.Frame.__init__(self, parent, wx.ID_ANY, title = 'Untitled Passage - ' + self.app.NAME, \
                          size = PassageFrame.DEFAULT_SIZE)

        # Passage menu

        passageMenu = wx.Menu()

        passageMenu.Append(PassageFrame.PASSAGE_EDIT_SELECTION,
                           'Create &Link From Selection\tCtrl-L')
        self.Bind(wx.EVT_MENU,
                  self.editSelection,
                  id=PassageFrame.PASSAGE_EDIT_SELECTION)

        self.outLinksMenu = wx.Menu()
        self.outLinksMenuTitle = passageMenu.AppendMenu(
            wx.ID_ANY, 'Outgoing Links', self.outLinksMenu)
        self.inLinksMenu = wx.Menu()
        self.inLinksMenuTitle = passageMenu.AppendMenu(wx.ID_ANY,
                                                       'Incoming Links',
                                                       self.inLinksMenu)
        self.brokenLinksMenu = wx.Menu()
        self.brokenLinksMenuTitle = passageMenu.AppendMenu(
            wx.ID_ANY, 'Broken Links', self.brokenLinksMenu)

        passageMenu.AppendSeparator()

        passageMenu.Append(wx.ID_SAVE, '&Save Story\tCtrl-S')
        self.Bind(wx.EVT_MENU, self.widget.parent.parent.save, id=wx.ID_SAVE)

        passageMenu.Append(PassageFrame.PASSAGE_REBUILD_STORY,
                           '&Rebuild Story\tCtrl-R')
        self.Bind(wx.EVT_MENU,
                  self.widget.parent.parent.rebuild,
                  id=PassageFrame.PASSAGE_REBUILD_STORY)

        passageMenu.AppendSeparator()

        passageMenu.Append(PassageFrame.PASSAGE_FULLSCREEN,
                           '&Fullscreen View\tF12')
        self.Bind(wx.EVT_MENU,
                  self.openFullscreen,
                  id=PassageFrame.PASSAGE_FULLSCREEN)

        passageMenu.Append(wx.ID_CLOSE, '&Close Passage\tCtrl-W')
        self.Bind(wx.EVT_MENU, lambda e: self.Destroy(), id=wx.ID_CLOSE)

        # Edit menu

        editMenu = wx.Menu()

        editMenu.Append(wx.ID_UNDO, '&Undo\tCtrl-Z')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Undo(), id=wx.ID_UNDO)

        editMenu.Append(wx.ID_REDO, '&Redo\tCtrl-Y')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Redo(), id=wx.ID_REDO)

        editMenu.AppendSeparator()

        editMenu.Append(wx.ID_CUT, 'Cu&t\tCtrl-X')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Cut(), id=wx.ID_CUT)

        editMenu.Append(wx.ID_COPY, '&Copy\tCtrl-C')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Copy(), id=wx.ID_COPY)

        editMenu.Append(wx.ID_PASTE, '&Paste\tCtrl-V')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.bodyInput.Paste(),
                  id=wx.ID_PASTE)

        editMenu.Append(wx.ID_SELECTALL, 'Select &All\tCtrl-A')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.bodyInput.SelectAll(),
                  id=wx.ID_SELECTALL)

        editMenu.AppendSeparator()

        editMenu.Append(wx.ID_FIND, '&Find...\tCtrl-F')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.showSearchFrame(PassageSearchFrame.FIND_TAB),
                  id=wx.ID_FIND)

        editMenu.Append(PassageFrame.EDIT_FIND_NEXT, 'Find &Next\tCtrl-G')
        self.Bind(wx.EVT_MENU,
                  self.findNextRegexp,
                  id=PassageFrame.EDIT_FIND_NEXT)

        if sys.platform == 'darwin':
            shortcut = 'Ctrl-Shift-H'
        else:
            shortcut = 'Ctrl-H'

        editMenu.Append(wx.ID_REPLACE, '&Replace...\t' + shortcut)
        self.Bind(
            wx.EVT_MENU,
            lambda e: self.showSearchFrame(PassageSearchFrame.REPLACE_TAB),
            id=wx.ID_REPLACE)

        # menus

        self.menus = wx.MenuBar()
        self.menus.Append(passageMenu, '&Passage')
        self.menus.Append(editMenu, '&Edit')
        self.SetMenuBar(self.menus)

        # controls

        self.panel = wx.Panel(self)
        allSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(allSizer)

        # title/tag controls

        self.topControls = wx.Panel(self.panel)
        topSizer = wx.FlexGridSizer(3, 2, metrics.size('relatedControls'),
                                    metrics.size('relatedControls'))

        titleLabel = wx.StaticText(self.topControls,
                                   style=wx.ALIGN_RIGHT,
                                   label=PassageFrame.TITLE_LABEL)
        self.titleInput = wx.TextCtrl(self.topControls)
        tagsLabel = wx.StaticText(self.topControls,
                                  style=wx.ALIGN_RIGHT,
                                  label=PassageFrame.TAGS_LABEL)
        self.tagsInput = wx.TextCtrl(self.topControls)
        topSizer.Add(titleLabel,
                     0,
                     flag=wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(self.titleInput,
                     1,
                     flag=wx.EXPAND | wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(tagsLabel,
                     0,
                     flag=wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(self.tagsInput,
                     1,
                     flag=wx.EXPAND | wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.AddGrowableCol(1, 1)
        self.topControls.SetSizer(topSizer)

        # body text

        class Canvoid:
            def __init__(self, template=None, serial=None):
                self.points = []
                # Defaults
                if template:
                    self.penColor = template.penColor
                    self.brushColor = template.brushColor
                else:
                    self.penColor = "BLACK"
                    self.brushColor = "RED"
                # Override
                if serial:
                    self.penColor = serial["penColor"]
                    self.brushColor = serial["brushColor"]
                    for point in serial["points"]:
                        self.points.append(wx.Point(point[0],
                                                    point[1]))  # From tuple

            @staticmethod
            def initFrom(serial):
                return Canvoid(serial=serial)

            def pop(self):
                self.points.pop()

            def serialize(self):
                return {
                    "points": map(wx.Point.Get, self.points),  # Map to tuples
                    "brushColor": self.brushColor,
                    "penColor": self.penColor,
                }

        class DrawPanelUpdateEvent(wx.PyEvent):
            pass

        class DrawPanel(wx.Panel):
            """Draw a line to a panel."""

            CROSS = 5
            EVT_UPDATE_ID = wx.NewEventType()
            EVT_UPDATE = wx.PyEventBinder(EVT_UPDATE_ID, 1)

            def __init__(self, parent):
                wx.Panel.__init__(self, parent)
                self.Bind(wx.EVT_PAINT, self.OnPaint)
                self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
                self.Bind(wx.EVT_MOTION, self.OnMove)
                self.resetFrom()

            def resetFrom(self, serial=None):
                if serial:
                    canvoids = map(Canvoid.initFrom, serial["canvoids"])
                else:
                    canvoids = []

                self.canvoids = canvoids
                self.SetBackgroundColour("WHITE")
                self.currentCanvoid = None
                self.transientPoint = None
                self.currentCursor = None
                self.transientCircle = False
                if serial:
                    self.Refresh()

            def serialize(self):
                return {
                    "canvoids": map(Canvoid.serialize, self.canvoids),
                }

            def OnPaint(self, event=None):
                dc = wx.PaintDC(self)
                dc.Clear()
                for canvoid in self.canvoids:
                    dc.SetPen(wx.Pen(canvoid.penColor, 4))
                    dc.SetBrush(wx.Brush(canvoid.brushColor))
                    dc.DrawPolygon(canvoid.points)
                if self.currentCursor:
                    dc.SetPen(wx.Pen("BLACK", 1))
                    if not self.transientCircle:
                        dc.DrawLine(self.currentCursor.x - DrawPanel.CROSS,
                                    self.currentCursor.y + DrawPanel.CROSS,
                                    self.currentCursor.x + DrawPanel.CROSS,
                                    self.currentCursor.y - DrawPanel.CROSS)
                        dc.DrawLine(self.currentCursor.x - DrawPanel.CROSS,
                                    self.currentCursor.y - DrawPanel.CROSS,
                                    self.currentCursor.x + DrawPanel.CROSS,
                                    self.currentCursor.y + DrawPanel.CROSS)
                    else:
                        dc.SetBrush(wx.Brush("WHITE", wx.TRANSPARENT))
                        dc.DrawCirclePoint(self.transientPoint, 10)

            def cap(self):
                if self.transientPoint:
                    self.currentCanvoid.pop()
                self.currentCanvoid = None
                self.transientPoint = None
                self.transientCircle = False
                wx.PostEvent(
                    self.GetEventHandler(),
                    DrawPanelUpdateEvent(self.GetId(),
                                         DrawPanel.EVT_UPDATE_ID))

            def OnClick(self, event=None):
                position = event.GetPosition()
                self.currentCursor = position
                if self.transientCircle:
                    self.cap()
                else:
                    if not self.currentCanvoid:
                        self.currentCanvoid = Canvoid()
                        self.currentCanvoid.points.append(position)
                        self.canvoids.append(self.currentCanvoid)
                    self.transientPoint = wx.Point(position.x, position.y)
                    self.currentCanvoid.points.append(self.transientPoint)
                self.Refresh()

            def OnMove(self, event=None):
                self.currentCursor = event.GetPosition()
                if self.transientPoint:

                    def pointDistSq(a, b):
                        c = a - b
                        return c.x * c.x + c.y * c.y

                    def pointCopy(a, b):
                        a.x = b.x
                        a.y = b.y

                    initPoint = self.currentCanvoid.points[0]
                    self.transientCircle = len(
                        self.currentCanvoid.points) > 2 and pointDistSq(
                            initPoint, self.currentCursor) < 100

                    if self.transientCircle:
                        pointCopy(self.transientPoint, initPoint)
                    else:
                        pointCopy(self.transientPoint, self.currentCursor)

                self.Refresh()

        self.drawInput = DrawPanel(self.panel)

        self.bodyInput = wx.stc.StyledTextCtrl(self.panel,
                                               style=wx.TE_PROCESS_TAB
                                               | wx.BORDER_SUNKEN)
        self.bodyInput.SetUseHorizontalScrollBar(False)
        self.bodyInput.SetMargins(8, 8)
        self.bodyInput.SetMarginWidth(1, 0)
        self.bodyInput.SetWrapMode(wx.stc.STC_WRAP_WORD)
        self.bodyInput.SetSelBackground(
            True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
        self.bodyInput.SetSelForeground(
            True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))

        # The default keyboard shortcuts for StyledTextCtrl are
        # nonstandard on Mac OS X
        if sys.platform == "darwin":
            # cmd-left/right to move to beginning/end of line
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_LEFT,
                                        wx.stc.STC_SCMOD_CTRL,
                                        wx.stc.STC_CMD_HOMEDISPLAY)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_LEFT,
                wx.stc.STC_SCMOD_CTRL | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_HOMEDISPLAYEXTEND)
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_RIGHT,
                                        wx.stc.STC_SCMOD_CTRL,
                                        wx.stc.STC_CMD_LINEENDDISPLAY)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_RIGHT,
                wx.stc.STC_SCMOD_CTRL | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_LINEENDDISPLAYEXTEND)
            # opt-left/right to move forward/back a word
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_LEFT,
                                        wx.stc.STC_SCMOD_ALT,
                                        wx.stc.STC_CMD_WORDLEFT)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_LEFT,
                wx.stc.STC_SCMOD_ALT | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_WORDLEFTEXTEND)
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_RIGHT,
                                        wx.stc.STC_SCMOD_ALT,
                                        wx.stc.STC_CMD_WORDRIGHT)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_RIGHT,
                wx.stc.STC_SCMOD_ALT | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_WORDRIGHTEXTEND)
            # cmd-delete to delete from the cursor to beginning of line
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_BACK,
                                        wx.stc.STC_SCMOD_CTRL,
                                        wx.stc.STC_CMD_DELLINELEFT)
            # opt-delete to delete the previous/current word
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_BACK,
                                        wx.stc.STC_SCMOD_ALT,
                                        wx.stc.STC_CMD_DELWORDLEFT)
            # cmd-shift-z to redo
            self.bodyInput.CmdKeyAssign(
                ord('Z'), wx.stc.STC_SCMOD_CTRL | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_REDO)

        # final layout

        allSizer.Add(self.topControls,
                     flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND,
                     border=metrics.size('windowBorder'))
        allSizer.Add(self.drawInput,
                     proportion=1,
                     flag=wx.TOP | wx.EXPAND,
                     border=metrics.size('relatedControls'))
        allSizer.Add(self.bodyInput,
                     proportion=1,
                     flag=wx.TOP | wx.EXPAND,
                     border=metrics.size('relatedControls'))
        self.lexer = TweeLexer(self.bodyInput, self)
        self.applyPrefs()
        self.syncInputs()
        self.bodyInput.EmptyUndoBuffer()
        self.updateSubmenus()
        self.setLexer()

        # event bindings
        # we need to do this AFTER setting up initial values

        self.titleInput.Bind(wx.EVT_TEXT, self.syncPassage)
        self.tagsInput.Bind(wx.EVT_TEXT, self.syncPassage)
        self.bodyInput.Bind(wx.stc.EVT_STC_CHANGE, self.syncPassage)
        self.drawInput.Bind(DrawPanel.EVT_UPDATE, self.syncPassage)
        self.bodyInput.Bind(wx.stc.EVT_STC_START_DRAG, self.prepDrag)
        self.Bind(wx.EVT_CLOSE, self.closeFullscreen)
        self.Bind(wx.EVT_MENU_OPEN, self.updateSubmenus)
        self.Bind(wx.EVT_UPDATE_UI, self.updateUI)

        if not re.match('Untitled Passage \d+', self.widget.passage.title):
            self.bodyInput.SetFocus()
            self.bodyInput.SetSelection(-1, -1)

        self.SetIcon(self.app.icon)
        self.Show(True)
Exemplo n.º 2
0
    def __init__(self, parent, widget, app):
        self.widget = widget
        self.app = app
        self.syncTimer = None
        self.lastFindRegexp = None
        self.lastFindFlags = None
        self.usingLexer = True

        wx.Frame.__init__(self, parent, wx.ID_ANY, title = 'Untitled Passage - ' + self.app.NAME, \
                          size = PassageFrame.DEFAULT_SIZE)

        # Passage menu

        passageMenu = wx.Menu()

        passageMenu.Append(PassageFrame.PASSAGE_EDIT_SELECTION,
                           'Create &Link From Selection\tCtrl-L')
        self.Bind(wx.EVT_MENU,
                  self.editSelection,
                  id=PassageFrame.PASSAGE_EDIT_SELECTION)

        self.outLinksMenu = wx.Menu()
        self.outLinksMenuTitle = passageMenu.AppendMenu(
            wx.ID_ANY, 'Outgoing Links', self.outLinksMenu)
        self.inLinksMenu = wx.Menu()
        self.inLinksMenuTitle = passageMenu.AppendMenu(wx.ID_ANY,
                                                       'Incoming Links',
                                                       self.inLinksMenu)
        self.brokenLinksMenu = wx.Menu()
        self.brokenLinksMenuTitle = passageMenu.AppendMenu(
            wx.ID_ANY, 'Broken Links', self.brokenLinksMenu)

        passageMenu.AppendSeparator()

        passageMenu.Append(wx.ID_SAVE, '&Save Story\tCtrl-S')
        self.Bind(wx.EVT_MENU, self.widget.parent.parent.save, id=wx.ID_SAVE)

        passageMenu.Append(PassageFrame.PASSAGE_REBUILD_STORY,
                           '&Rebuild Story\tCtrl-R')
        self.Bind(wx.EVT_MENU,
                  self.widget.parent.parent.rebuild,
                  id=PassageFrame.PASSAGE_REBUILD_STORY)

        passageMenu.AppendSeparator()

        passageMenu.Append(PassageFrame.PASSAGE_FULLSCREEN,
                           '&Fullscreen View\tF12')
        self.Bind(wx.EVT_MENU,
                  self.openFullscreen,
                  id=PassageFrame.PASSAGE_FULLSCREEN)

        passageMenu.Append(wx.ID_CLOSE, '&Close Passage\tCtrl-W')
        self.Bind(wx.EVT_MENU, lambda e: self.Destroy(), id=wx.ID_CLOSE)

        # Edit menu

        editMenu = wx.Menu()

        editMenu.Append(wx.ID_UNDO, '&Undo\tCtrl-Z')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Undo(), id=wx.ID_UNDO)

        editMenu.Append(wx.ID_REDO, '&Redo\tCtrl-Y')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Redo(), id=wx.ID_REDO)

        editMenu.AppendSeparator()

        editMenu.Append(wx.ID_CUT, 'Cu&t\tCtrl-X')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Cut(), id=wx.ID_CUT)

        editMenu.Append(wx.ID_COPY, '&Copy\tCtrl-C')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Copy(), id=wx.ID_COPY)

        editMenu.Append(wx.ID_PASTE, '&Paste\tCtrl-V')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.bodyInput.Paste(),
                  id=wx.ID_PASTE)

        editMenu.Append(wx.ID_SELECTALL, 'Select &All\tCtrl-A')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.bodyInput.SelectAll(),
                  id=wx.ID_SELECTALL)

        editMenu.AppendSeparator()

        editMenu.Append(wx.ID_FIND, '&Find...\tCtrl-F')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.showSearchFrame(PassageSearchFrame.FIND_TAB),
                  id=wx.ID_FIND)

        editMenu.Append(PassageFrame.EDIT_FIND_NEXT, 'Find &Next\tCtrl-G')
        self.Bind(wx.EVT_MENU,
                  self.findNextRegexp,
                  id=PassageFrame.EDIT_FIND_NEXT)

        if sys.platform == 'darwin':
            shortcut = 'Ctrl-Shift-H'
        else:
            shortcut = 'Ctrl-H'

        editMenu.Append(wx.ID_REPLACE, '&Replace...\t' + shortcut)
        self.Bind(
            wx.EVT_MENU,
            lambda e: self.showSearchFrame(PassageSearchFrame.REPLACE_TAB),
            id=wx.ID_REPLACE)

        # menus

        self.menus = wx.MenuBar()
        self.menus.Append(passageMenu, '&Passage')
        self.menus.Append(editMenu, '&Edit')
        self.SetMenuBar(self.menus)

        # controls

        self.panel = wx.Panel(self)
        allSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(allSizer)

        # title/tag controls

        self.topControls = wx.Panel(self.panel)
        topSizer = wx.FlexGridSizer(3, 2, metrics.size('relatedControls'),
                                    metrics.size('relatedControls'))

        titleLabel = wx.StaticText(self.topControls,
                                   style=wx.ALIGN_RIGHT,
                                   label=PassageFrame.TITLE_LABEL)
        self.titleInput = wx.TextCtrl(self.topControls)
        tagsLabel = wx.StaticText(self.topControls,
                                  style=wx.ALIGN_RIGHT,
                                  label=PassageFrame.TAGS_LABEL)
        self.tagsInput = wx.TextCtrl(self.topControls)
        topSizer.Add(titleLabel,
                     0,
                     flag=wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(self.titleInput,
                     1,
                     flag=wx.EXPAND | wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(tagsLabel,
                     0,
                     flag=wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(self.tagsInput,
                     1,
                     flag=wx.EXPAND | wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.AddGrowableCol(1, 1)
        self.topControls.SetSizer(topSizer)

        # body text

        self.bodyInput = wx.stc.StyledTextCtrl(self.panel,
                                               style=wx.TE_PROCESS_TAB
                                               | wx.BORDER_SUNKEN)
        self.bodyInput.SetUseHorizontalScrollBar(False)
        self.bodyInput.SetMargins(8, 8)
        self.bodyInput.SetMarginWidth(1, 0)
        self.bodyInput.SetWrapMode(wx.stc.STC_WRAP_WORD)
        self.bodyInput.SetSelBackground(
            True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
        self.bodyInput.SetSelForeground(
            True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))

        # final layout

        allSizer.Add(self.topControls,
                     flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND,
                     border=metrics.size('windowBorder'))
        allSizer.Add(self.bodyInput,
                     proportion=1,
                     flag=wx.TOP | wx.EXPAND,
                     border=metrics.size('relatedControls'))
        self.lexer = TweeLexer(self.bodyInput, self)
        self.applyPrefs()
        self.syncInputs()
        self.bodyInput.EmptyUndoBuffer()
        self.updateSubmenus()
        self.setLexer()

        # event bindings
        # we need to do this AFTER setting up initial values

        self.titleInput.Bind(wx.EVT_TEXT, self.syncPassage)
        self.tagsInput.Bind(wx.EVT_TEXT, self.syncPassage)
        self.bodyInput.Bind(wx.stc.EVT_STC_CHANGE, self.syncPassage)
        self.bodyInput.Bind(wx.stc.EVT_STC_START_DRAG, self.prepDrag)
        self.Bind(wx.EVT_CLOSE, self.closeFullscreen)
        self.Bind(wx.EVT_MENU_OPEN, self.updateSubmenus)
        self.Bind(wx.EVT_UPDATE_UI, self.updateUI)

        if not re.match('Untitled Passage \d+', self.widget.passage.title):
            self.bodyInput.SetFocus()
            self.bodyInput.SetSelection(-1, -1)

        self.SetIcon(self.app.icon)
        self.Show(True)
Exemplo n.º 3
0
    def __init__(self, parent, widget, app):
        self.widget = widget
        self.app = app
        self.syncTimer = None
        self.lastFindRegexp = None
        self.lastFindFlags = None
        self.usingLexer = self.LEXER_NORMAL
        self.titleInvalid = False

        wx.Frame.__init__(self, parent, wx.ID_ANY, title = 'Untitled Passage - ' + self.app.NAME + ' ' + versionString, \
                          size = PassageFrame.DEFAULT_SIZE)

        # Passage menu

        passageMenu = wx.Menu()

        passageMenu.Append(PassageFrame.PASSAGE_EDIT_SELECTION,
                           'Create &Link From Selection\tCtrl-L')
        self.Bind(wx.EVT_MENU,
                  self.editSelection,
                  id=PassageFrame.PASSAGE_EDIT_SELECTION)

        self.outLinksMenu = wx.Menu()
        self.outLinksMenuTitle = passageMenu.AppendMenu(
            wx.ID_ANY, 'Outgoing Links', self.outLinksMenu)
        self.inLinksMenu = wx.Menu()
        self.inLinksMenuTitle = passageMenu.AppendMenu(wx.ID_ANY,
                                                       'Incoming Links',
                                                       self.inLinksMenu)
        self.brokenLinksMenu = wx.Menu()
        self.brokenLinksMenuTitle = passageMenu.AppendMenu(
            wx.ID_ANY, 'Broken Links', self.brokenLinksMenu)

        passageMenu.AppendSeparator()

        passageMenu.Append(wx.ID_SAVE, '&Save Story\tCtrl-S')
        self.Bind(wx.EVT_MENU, self.widget.parent.parent.save, id=wx.ID_SAVE)

        passageMenu.Append(PassageFrame.PASSAGE_VERIFY,
                           '&Verify Passage\tCtrl-E')
        self.Bind(wx.EVT_MENU, lambda e: (self.widget.verifyPassage(self), self.offerAssistance()),\
                  id = PassageFrame.PASSAGE_VERIFY)

        passageMenu.Append(PassageFrame.PASSAGE_TEST_HERE,
                           '&Test Play From Here\tCtrl-T')
        self.Bind(wx.EVT_MENU, lambda e: self.widget.parent.parent.testBuild(e, startAt = self.widget.passage.title),\
                  id = PassageFrame.PASSAGE_TEST_HERE)

        passageMenu.Append(PassageFrame.PASSAGE_REBUILD_STORY,
                           '&Rebuild Story\tCtrl-R')
        self.Bind(wx.EVT_MENU,
                  self.widget.parent.parent.rebuild,
                  id=PassageFrame.PASSAGE_REBUILD_STORY)

        passageMenu.AppendSeparator()

        passageMenu.Append(PassageFrame.PASSAGE_FULLSCREEN,
                           '&Fullscreen View\tF12')
        self.Bind(wx.EVT_MENU,
                  self.openFullscreen,
                  id=PassageFrame.PASSAGE_FULLSCREEN)

        passageMenu.Append(wx.ID_CLOSE, '&Close Passage\tCtrl-W')
        self.Bind(wx.EVT_MENU, lambda e: self.Close(), id=wx.ID_CLOSE)

        # Edit menu

        editMenu = wx.Menu()

        editMenu.Append(wx.ID_UNDO, '&Undo\tCtrl-Z')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Undo(), id=wx.ID_UNDO)

        if sys.platform == 'darwin':
            shortcut = 'Ctrl-Shift-Z'
        else:
            shortcut = 'Ctrl-Y'

        editMenu.Append(wx.ID_REDO, '&Redo\t' + shortcut)
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Redo(), id=wx.ID_REDO)

        editMenu.AppendSeparator()

        editMenu.Append(wx.ID_CUT, 'Cu&t\tCtrl-X')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Cut(), id=wx.ID_CUT)

        editMenu.Append(wx.ID_COPY, '&Copy\tCtrl-C')
        self.Bind(wx.EVT_MENU, lambda e: self.bodyInput.Copy(), id=wx.ID_COPY)

        editMenu.Append(wx.ID_PASTE, '&Paste\tCtrl-V')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.bodyInput.Paste(),
                  id=wx.ID_PASTE)

        editMenu.Append(wx.ID_SELECTALL, 'Select &All\tCtrl-A')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.bodyInput.SelectAll(),
                  id=wx.ID_SELECTALL)

        editMenu.AppendSeparator()

        editMenu.Append(wx.ID_FIND, '&Find...\tCtrl-F')
        self.Bind(wx.EVT_MENU,
                  lambda e: self.showSearchFrame(PassageSearchFrame.FIND_TAB),
                  id=wx.ID_FIND)

        editMenu.Append(PassageFrame.EDIT_FIND_NEXT, 'Find &Next\tCtrl-G')
        self.Bind(wx.EVT_MENU,
                  self.findNextRegexp,
                  id=PassageFrame.EDIT_FIND_NEXT)

        if sys.platform == 'darwin':
            shortcut = 'Ctrl-Shift-H'
        else:
            shortcut = 'Ctrl-H'

        editMenu.Append(wx.ID_REPLACE, '&Replace...\t' + shortcut)
        self.Bind(
            wx.EVT_MENU,
            lambda e: self.showSearchFrame(PassageSearchFrame.REPLACE_TAB),
            id=wx.ID_REPLACE)

        # help menu

        helpMenu = wx.Menu()

        helpMenu.Append(PassageFrame.HELP1, 'About Passages')
        self.Bind(wx.EVT_MENU,
                  lambda e: wx.LaunchDefaultBrowser(
                      'http://twinery.org/wiki/passage'),
                  id=PassageFrame.HELP1)

        helpMenu.Append(PassageFrame.HELP2, 'About Text Syntax')
        self.Bind(wx.EVT_MENU,
                  lambda e: wx.LaunchDefaultBrowser(
                      'http://twinery.org/wiki/syntax'),
                  id=PassageFrame.HELP2)

        helpMenu.Append(PassageFrame.HELP3, 'About Links')
        self.Bind(
            wx.EVT_MENU,
            lambda e: wx.LaunchDefaultBrowser('http://twinery.org/wiki/link'),
            id=PassageFrame.HELP3)

        helpMenu.Append(PassageFrame.HELP4, 'About Tags')
        self.Bind(
            wx.EVT_MENU,
            lambda e: wx.LaunchDefaultBrowser('http://twinery.org/wiki/tag'),
            id=PassageFrame.HELP4)

        # menus

        self.menus = wx.MenuBar()
        self.menus.Append(passageMenu, '&Passage')
        self.menus.Append(editMenu, '&Edit')
        self.menus.Append(helpMenu, '&Help')
        self.SetMenuBar(self.menus)

        # controls

        self.panel = wx.Panel(self)
        allSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(allSizer)

        # title/tag controls

        self.topControls = wx.Panel(self.panel)
        topSizer = wx.FlexGridSizer(3, 2, metrics.size('relatedControls'),
                                    metrics.size('relatedControls'))

        self.titleLabel = wx.StaticText(self.topControls,
                                        style=wx.ALIGN_RIGHT,
                                        label=PassageFrame.TITLE_LABEL)
        self.titleInput = wx.TextCtrl(self.topControls)
        tagsLabel = wx.StaticText(self.topControls,
                                  style=wx.ALIGN_RIGHT,
                                  label=PassageFrame.TAGS_LABEL)
        self.tagsInput = wx.TextCtrl(self.topControls)
        topSizer.Add(self.titleLabel,
                     0,
                     flag=wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(self.titleInput,
                     1,
                     flag=wx.EXPAND | wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(tagsLabel,
                     0,
                     flag=wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.Add(self.tagsInput,
                     1,
                     flag=wx.EXPAND | wx.ALL,
                     border=metrics.size('focusRing'))
        topSizer.AddGrowableCol(1, 1)
        self.topControls.SetSizer(topSizer)

        # body text

        self.bodyInput = wx.stc.StyledTextCtrl(self.panel,
                                               style=wx.TE_PROCESS_TAB
                                               | wx.BORDER_SUNKEN)
        self.bodyInput.SetUseHorizontalScrollBar(False)
        self.bodyInput.SetMargins(8, 8)
        self.bodyInput.SetMarginWidth(1, 0)
        self.bodyInput.SetWrapMode(wx.stc.STC_WRAP_WORD)
        self.bodyInput.SetSelBackground(
            True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
        self.bodyInput.SetSelForeground(
            True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))

        # The default keyboard shortcuts for StyledTextCtrl are
        # nonstandard on Mac OS X
        if sys.platform == "darwin":
            # cmd-left/right to move to beginning/end of line
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_LEFT,
                                        wx.stc.STC_SCMOD_CTRL,
                                        wx.stc.STC_CMD_HOMEDISPLAY)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_LEFT,
                wx.stc.STC_SCMOD_CTRL | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_HOMEDISPLAYEXTEND)
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_RIGHT,
                                        wx.stc.STC_SCMOD_CTRL,
                                        wx.stc.STC_CMD_LINEENDDISPLAY)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_RIGHT,
                wx.stc.STC_SCMOD_CTRL | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_LINEENDDISPLAYEXTEND)
            # opt-left/right to move forward/back a word
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_LEFT,
                                        wx.stc.STC_SCMOD_ALT,
                                        wx.stc.STC_CMD_WORDLEFT)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_LEFT,
                wx.stc.STC_SCMOD_ALT | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_WORDLEFTEXTEND)
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_RIGHT,
                                        wx.stc.STC_SCMOD_ALT,
                                        wx.stc.STC_CMD_WORDRIGHT)
            self.bodyInput.CmdKeyAssign(
                wx.stc.STC_KEY_RIGHT,
                wx.stc.STC_SCMOD_ALT | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_WORDRIGHTEXTEND)
            # cmd-delete to delete from the cursor to beginning of line
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_BACK,
                                        wx.stc.STC_SCMOD_CTRL,
                                        wx.stc.STC_CMD_DELLINELEFT)
            # opt-delete to delete the previous/current word
            self.bodyInput.CmdKeyAssign(wx.stc.STC_KEY_BACK,
                                        wx.stc.STC_SCMOD_ALT,
                                        wx.stc.STC_CMD_DELWORDLEFT)
            # cmd-shift-z to redo
            self.bodyInput.CmdKeyAssign(
                ord('Z'), wx.stc.STC_SCMOD_CTRL | wx.stc.STC_SCMOD_SHIFT,
                wx.stc.STC_CMD_REDO)

        # final layout

        allSizer.Add(self.topControls,
                     flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND,
                     border=metrics.size('windowBorder'))
        allSizer.Add(self.bodyInput,
                     proportion=1,
                     flag=wx.TOP | wx.EXPAND,
                     border=metrics.size('relatedControls'))
        self.lexer = TweeLexer(self.bodyInput, self)
        self.applyPrefs()
        self.syncInputs()
        self.bodyInput.EmptyUndoBuffer()
        self.updateSubmenus()
        self.setLexer()

        # event bindings
        # we need to do this AFTER setting up initial values

        self.titleInput.Bind(wx.EVT_TEXT, self.syncPassage)
        self.tagsInput.Bind(wx.EVT_TEXT, self.syncPassage)
        self.bodyInput.Bind(wx.stc.EVT_STC_CHANGE, self.syncPassage)
        self.bodyInput.Bind(wx.stc.EVT_STC_START_DRAG, self.prepDrag)
        self.Bind(wx.EVT_CLOSE, self.closeEditor)
        self.Bind(wx.EVT_MENU_OPEN, self.updateSubmenus)
        self.Bind(wx.EVT_UPDATE_UI, self.updateUI)

        if not re.match('Untitled Passage \d+', self.widget.passage.title):
            self.bodyInput.SetFocus()
            self.bodyInput.SetSelection(-1, -1)

        # Hack to force titles (>18 char) to display correctly.
        # NOTE: stops working if moved above bodyInput code.
        self.titleInput.SetInsertionPoint(0)

        self.SetIcon(self.app.icon)
        self.Show(True)