def __init__(self, parent, app, state=None): wx.Frame.__init__(self, parent, wx.ID_ANY, title = StoryFrame.DEFAULT_TITLE, \ size = StoryFrame.DEFAULT_SIZE) self.app = app self.parent = parent self.pristine = True # the user has not added any content to this at all self.dirty = False # the user has not made unsaved changes self.storyFormats = {} # list of available story formats # inner state if (state): self.buildDestination = state['buildDestination'] self.saveDestination = state['saveDestination'] self.target = state['target'] self.storyPanel = StoryPanel(self, app, state=state['storyPanel']) self.pristine = False else: self.buildDestination = '' self.saveDestination = '' self.target = 'sugarcube' self.storyPanel = StoryPanel(self, app) # window events self.Bind(wx.EVT_CLOSE, self.checkClose) self.Bind(wx.EVT_UPDATE_UI, self.updateUI) # Timer for the auto build file watcher self.autobuildtimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.autoBuildTick, self.autobuildtimer) # File menu fileMenu = wx.Menu() fileMenu.Append(wx.ID_NEW, '&New Story\tCtrl-Shift-N') self.Bind(wx.EVT_MENU, self.app.newStory, id=wx.ID_NEW) fileMenu.Append(wx.ID_OPEN, '&Open Story...\tCtrl-O') self.Bind(wx.EVT_MENU, self.app.openDialog, id=wx.ID_OPEN) recentFilesMenu = wx.Menu() self.recentFiles = wx.FileHistory(self.app.RECENT_FILES) self.recentFiles.Load(self.app.config) self.app.verifyRecentFiles(self) self.recentFiles.UseMenu(recentFilesMenu) self.recentFiles.AddFilesToThisMenu(recentFilesMenu) fileMenu.AppendMenu(wx.ID_ANY, 'Open &Recent', recentFilesMenu) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 0), id=wx.ID_FILE1) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 1), id=wx.ID_FILE2) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 2), id=wx.ID_FILE3) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 3), id=wx.ID_FILE4) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 4), id=wx.ID_FILE5) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 5), id=wx.ID_FILE6) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 6), id=wx.ID_FILE7) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 7), id=wx.ID_FILE8) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 8), id=wx.ID_FILE9) self.Bind(wx.EVT_MENU, lambda e: self.app.openRecent(self, 9), id=wx.ID_FILE9 + 1) fileMenu.AppendSeparator() fileMenu.Append(wx.ID_SAVE, '&Save Story\tCtrl-S') self.Bind(wx.EVT_MENU, self.save, id=wx.ID_SAVE) fileMenu.Append(wx.ID_SAVEAS, 'S&ave Story As...\tCtrl-Shift-S') self.Bind(wx.EVT_MENU, self.saveAs, id=wx.ID_SAVEAS) fileMenu.Append(wx.ID_REVERT_TO_SAVED, '&Revert to Saved') self.Bind(wx.EVT_MENU, self.revert, id=wx.ID_REVERT_TO_SAVED) fileMenu.AppendSeparator() fileMenu.Append(StoryFrame.FILE_EXPORT_PROOF, 'Export &Proofing Copy...') self.Bind(wx.EVT_MENU, self.proof, id=StoryFrame.FILE_EXPORT_PROOF) fileMenu.Append(StoryFrame.FILE_IMPORT_SOURCE, '&Import Source Code...') self.Bind(wx.EVT_MENU, self.importSource, id=StoryFrame.FILE_IMPORT_SOURCE) fileMenu.Append(StoryFrame.FILE_EXPORT_SOURCE, 'Export Source &Code...') self.Bind(wx.EVT_MENU, self.exportSource, id=StoryFrame.FILE_EXPORT_SOURCE) fileMenu.AppendSeparator() fileMenu.Append(wx.ID_CLOSE, '&Close Story\tCtrl-W') self.Bind(wx.EVT_MENU, self.checkCloseMenu, id=wx.ID_CLOSE) fileMenu.Append(wx.ID_EXIT, 'E&xit Twine\tCtrl-Q') self.Bind(wx.EVT_MENU, lambda e: self.app.exit(), id=wx.ID_EXIT) # Edit menu editMenu = wx.Menu() editMenu.Append(wx.ID_UNDO, '&Undo\tCtrl-Z') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.undo(), id=wx.ID_UNDO) editMenu.Append(wx.ID_REDO, '&Redo\tCtrl-Y') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.redo(), id=wx.ID_REDO) editMenu.AppendSeparator() editMenu.Append(wx.ID_CUT, 'Cu&t\tCtrl-X') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.cutWidgets(), id=wx.ID_CUT) editMenu.Append(wx.ID_COPY, '&Copy\tCtrl-C') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.copyWidgets(), id=wx.ID_COPY) editMenu.Append(wx.ID_PASTE, '&Paste\tCtrl-V') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.pasteWidgets(), id=wx.ID_PASTE) editMenu.Append(wx.ID_DELETE, '&Delete\tDel') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.removeWidgets(e, saveUndo=True), id=wx.ID_DELETE) editMenu.Append(wx.ID_SELECTALL, 'Select &All\tCtrl-A') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.eachWidget(lambda i: i.setSelected( True, exclusive=False)), id=wx.ID_SELECTALL) editMenu.AppendSeparator() editMenu.Append(wx.ID_FIND, 'Find...\tCtrl-F') self.Bind(wx.EVT_MENU, self.showFind, id=wx.ID_FIND) editMenu.Append(StoryFrame.EDIT_FIND_NEXT, 'Find Next\tCtrl-G') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.findWidgetRegexp(), id=StoryFrame.EDIT_FIND_NEXT) if sys.platform == 'darwin': shortcut = 'Ctrl-Shift-H' else: shortcut = 'Ctrl-H' editMenu.Append(wx.ID_REPLACE, 'Replace Across Entire Story...\t' + shortcut) self.Bind(wx.EVT_MENU, self.showReplace, id=wx.ID_REPLACE) editMenu.AppendSeparator() editMenu.Append(wx.ID_PREFERENCES, 'Preferences...\tCtrl-,') self.Bind(wx.EVT_MENU, self.app.showPrefs, id=wx.ID_PREFERENCES) # View menu viewMenu = wx.Menu() viewMenu.Append(wx.ID_ZOOM_IN, 'Zoom &In\t=') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.zoom('in'), id=wx.ID_ZOOM_IN) viewMenu.Append(wx.ID_ZOOM_OUT, 'Zoom &Out\t-') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.zoom('out'), id=wx.ID_ZOOM_OUT) viewMenu.Append(wx.ID_ZOOM_FIT, 'Zoom to &Fit\t0') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.zoom('fit'), id=wx.ID_ZOOM_FIT) viewMenu.Append(wx.ID_ZOOM_100, 'Zoom &100%\t1') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.zoom(1), id=wx.ID_ZOOM_100) viewMenu.AppendSeparator() viewMenu.Append(StoryFrame.VIEW_SNAP, 'Snap to &Grid', kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.toggleSnapping(), id=StoryFrame.VIEW_SNAP) viewMenu.Append(StoryFrame.VIEW_CLEANUP, '&Clean Up Passages') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.cleanup(), id=StoryFrame.VIEW_CLEANUP) viewMenu.AppendSeparator() viewMenu.Append(StoryFrame.VIEW_TOOLBAR, '&Toolbar', kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, self.toggleToolbar, id=StoryFrame.VIEW_TOOLBAR) # Story menu self.storyMenu = wx.Menu() self.storyMenu.Append(StoryFrame.STORY_NEW_PASSAGE, '&New Passage\tCtrl-N') self.Bind(wx.EVT_MENU, self.storyPanel.newWidget, id=StoryFrame.STORY_NEW_PASSAGE) self.storyMenu.Append(wx.ID_EDIT, '&Edit Passage\tCtrl-E') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.eachSelectedWidget(lambda w: w. openEditor(e)), id=wx.ID_EDIT) self.storyMenu.Append(StoryFrame.STORY_EDIT_FULLSCREEN, '&Edit Passage Text Fullscreen\tF12') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.eachSelectedWidget(lambda w: w.openEditor(e, fullscreen = True)), \ id = StoryFrame.STORY_EDIT_FULLSCREEN) self.storyMenu.Append(wx.ID_DELETE, '&Delete Passage') self.Bind(wx.EVT_MENU, lambda e: self.storyPanel.removeWidgets(e, saveUndo=True), id=wx.ID_DELETE) self.storyMenu.AppendSeparator() self.storyMenu.Append(StoryFrame.STORY_BUILD, '&Build Story...\tCtrl-B') self.Bind(wx.EVT_MENU, self.build, id=StoryFrame.STORY_BUILD) self.storyMenu.Append(StoryFrame.STORY_REBUILD, '&Rebuild Story\tCtrl-R') self.Bind(wx.EVT_MENU, self.rebuild, id=StoryFrame.STORY_REBUILD) self.storyMenu.Append(StoryFrame.STORY_VIEW_LAST, '&View Last Build\tCtrl-L') self.Bind(wx.EVT_MENU, self.viewBuild, id=StoryFrame.STORY_VIEW_LAST) self.autobuildmenuitem = self.storyMenu.Append( StoryFrame.STORY_AUTO_BUILD, '&Auto Build', kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, self.autoBuild, self.autobuildmenuitem) self.storyMenu.Check(StoryFrame.STORY_AUTO_BUILD, False) self.storyMenu.AppendSeparator() self.storyMenu.Append(StoryFrame.STORY_STATS, 'Story &Statistics\tCtrl-I') self.Bind(wx.EVT_MENU, self.stats, id=StoryFrame.STORY_STATS) # Story Format submenu storyFormatMenu = wx.Menu() storyFormatCounter = StoryFrame.STORY_FORMAT_BASE storyFormatPath = app.getPath() + os.sep + 'targets' + os.sep for sfdir in os.listdir(storyFormatPath): if os.access(storyFormatPath + sfdir + os.sep + 'header.html', os.R_OK): if sfdir == 'jonah': sfdirlabel = 'Jonah' elif sfdir == 'sugarcane': sfdirlabel = 'Sugarcane' elif sfdir == 'sugarcube': sfdirlabel = 'SugarCube' elif sfdir == 'tw': sfdirlabel = 'TW' elif sfdir == 'tw2': sfdirlabel = 'TW2' else: sfdirlabel = sfdir storyFormatMenu.Append(storyFormatCounter, sfdirlabel, kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, lambda e, target=sfdir: self.setTarget(target), id=storyFormatCounter) self.storyFormats[storyFormatCounter] = sfdir storyFormatCounter = storyFormatCounter + 1 storyFormatMenu.AppendSeparator() storyFormatMenu.Append(StoryFrame.STORY_FORMAT_HELP, '&About Story Formats') self.Bind(wx.EVT_MENU, lambda e: self.app.storyFormatHelp(), id=StoryFrame.STORY_FORMAT_HELP) self.storyMenu.AppendMenu(wx.ID_ANY, 'Story &Format', storyFormatMenu) # Help menu helpMenu = wx.Menu() helpMenu.Append(StoryFrame.HELP_MANUAL, 'Online &Help') self.Bind(wx.EVT_MENU, self.app.openDocs, id=StoryFrame.HELP_MANUAL) helpMenu.Append(StoryFrame.HELP_GROUP, '&Discuss Twine Online') self.Bind(wx.EVT_MENU, self.app.openGroup, id=StoryFrame.HELP_GROUP) helpMenu.Append(StoryFrame.HELP_BUG, 'Report a &Bug') self.Bind(wx.EVT_MENU, self.app.reportBug, id=StoryFrame.HELP_BUG) helpMenu.AppendSeparator() helpMenu.Append(wx.ID_ABOUT, '&About Twine') self.Bind(wx.EVT_MENU, self.app.about, id=wx.ID_ABOUT) # add menus self.menus = wx.MenuBar() self.menus.Append(fileMenu, '&File') self.menus.Append(editMenu, '&Edit') self.menus.Append(viewMenu, '&View') self.menus.Append(self.storyMenu, '&Story') self.menus.Append(helpMenu, '&Help') self.SetMenuBar(self.menus) # extra shortcuts self.SetAcceleratorTable(wx.AcceleratorTable([ \ (wx.ACCEL_NORMAL, wx.WXK_RETURN, wx.ID_EDIT), \ (wx.ACCEL_CTRL, wx.WXK_RETURN, StoryFrame.STORY_EDIT_FULLSCREEN) \ ])) # add toolbar iconPath = self.app.getPath() + os.sep + 'icons' + os.sep self.toolbar = self.CreateToolBar(style=wx.TB_FLAT | wx.TB_NODIVIDER) self.toolbar.SetToolBitmapSize( (StoryFrame.TOOLBAR_ICON_SIZE, StoryFrame.TOOLBAR_ICON_SIZE)) self.toolbar.AddLabelTool(StoryFrame.STORY_NEW_PASSAGE, 'New Passage', \ wx.Bitmap(iconPath + 'newpassage.png'), \ shortHelp = StoryFrame.NEW_PASSAGE_TOOLTIP) self.Bind(wx.EVT_TOOL, lambda e: self.storyPanel.newWidget(), id=StoryFrame.STORY_NEW_PASSAGE) self.toolbar.AddSeparator() self.toolbar.AddLabelTool(wx.ID_ZOOM_IN, 'Zoom In', \ wx.Bitmap(iconPath + 'zoomin.png'), \ shortHelp = StoryFrame.ZOOM_IN_TOOLTIP) self.Bind(wx.EVT_TOOL, lambda e: self.storyPanel.zoom('in'), id=wx.ID_ZOOM_IN) self.toolbar.AddLabelTool(wx.ID_ZOOM_OUT, 'Zoom Out', \ wx.Bitmap(iconPath + 'zoomout.png'), \ shortHelp = StoryFrame.ZOOM_OUT_TOOLTIP) self.Bind(wx.EVT_TOOL, lambda e: self.storyPanel.zoom('out'), id=wx.ID_ZOOM_OUT) self.toolbar.AddLabelTool(wx.ID_ZOOM_FIT, 'Zoom to Fit', \ wx.Bitmap(iconPath + 'zoomfit.png'), \ shortHelp = StoryFrame.ZOOM_FIT_TOOLTIP) self.Bind(wx.EVT_TOOL, lambda e: self.storyPanel.zoom('fit'), id=wx.ID_ZOOM_FIT) self.toolbar.AddLabelTool(wx.ID_ZOOM_100, 'Zoom to 100%', \ wx.Bitmap(iconPath + 'zoom1.png'), \ shortHelp = StoryFrame.ZOOM_ONE_TOOLTIP) self.Bind(wx.EVT_TOOL, lambda e: self.storyPanel.zoom(1.0), id=wx.ID_ZOOM_100) self.SetIcon(self.app.icon) if app.config.ReadBool('storyFrameToolbar'): self.showToolbar = True self.toolbar.Realize() else: self.showToolbar = False self.toolbar.Realize() self.toolbar.Hide()