PageRenderTime 40ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/trelby.py

https://github.com/alopex94/trelby
Python | 2694 lines | 2633 code | 50 blank | 11 comment | 17 complexity | 2253f888f34b03267a6d464885926b7a MD5 | raw file
Possible License(s): GPL-2.0
  1. # -*- coding: iso-8859-1 -*-
  2. from error import *
  3. import autocompletiondlg
  4. import cfgdlg
  5. import characterreport
  6. import charmapdlg
  7. import commandsdlg
  8. import config
  9. import dialoguechart
  10. import finddlg
  11. import gutil
  12. import headersdlg
  13. import locationreport
  14. import locationsdlg
  15. import misc
  16. import myimport
  17. import mypickle
  18. import namesdlg
  19. import opts
  20. import pml
  21. import scenereport
  22. import scriptreport
  23. import screenplay
  24. import spellcheck
  25. import spellcheckdlg
  26. import spellcheckcfgdlg
  27. import splash
  28. import titlesdlg
  29. import util
  30. import viewmode
  31. import watermarkdlg
  32. import copy
  33. import datetime
  34. import os
  35. import os.path
  36. import signal
  37. import sys
  38. import time
  39. import wx
  40. from functools import partial
  41. #keycodes
  42. KC_CTRL_A = 1
  43. KC_CTRL_B = 2
  44. KC_CTRL_D = 4
  45. KC_CTRL_E = 5
  46. KC_CTRL_F = 6
  47. KC_CTRL_N = 14
  48. KC_CTRL_P = 16
  49. KC_CTRL_V = 22
  50. VIEWMODE_DRAFT,\
  51. VIEWMODE_LAYOUT,\
  52. VIEWMODE_SIDE_BY_SIDE,\
  53. VIEWMODE_OVERVIEW_SMALL,\
  54. VIEWMODE_OVERVIEW_LARGE,\
  55. = range(5)
  56. def refreshGuiConfig():
  57. global cfgGui
  58. cfgGui = config.ConfigGui(cfgGl)
  59. def getCfgGui():
  60. return cfgGui
  61. # keeps (some) global data
  62. class GlobalData:
  63. def __init__(self):
  64. self.confFilename = misc.confPath + "/default.conf"
  65. self.stateFilename = misc.confPath + "/state"
  66. self.scDictFilename = misc.confPath + "/spell_checker_dictionary"
  67. # current script config path
  68. self.scriptSettingsPath = misc.confPath
  69. # global spell checker (user) dictionary
  70. self.scDict = spellcheck.Dict()
  71. # recently used files list
  72. self.mru = misc.MRUFiles(5)
  73. if opts.conf:
  74. self.confFilename = opts.conf
  75. v = self.cvars = mypickle.Vars()
  76. v.addInt("posX", 0, "PositionX", -20, 9999)
  77. v.addInt("posY", 0, "PositionY", -20, 9999)
  78. # linux has bigger font by default so it needs a wider window
  79. defaultW = 750
  80. if misc.isUnix:
  81. defaultW = 800
  82. v.addInt("width", defaultW, "Width", 500, 9999)
  83. v.addInt("height", 830, "Height", 300, 9999)
  84. v.addInt("viewMode", VIEWMODE_DRAFT, "ViewMode", VIEWMODE_DRAFT,
  85. VIEWMODE_OVERVIEW_LARGE)
  86. v.addList("files", [], "Files",
  87. mypickle.StrUnicodeVar("", u"", ""))
  88. v.makeDicts()
  89. v.setDefaults(self)
  90. self.height = min(self.height,
  91. wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) - 50)
  92. self.vmDraft = viewmode.ViewModeDraft()
  93. self.vmLayout = viewmode.ViewModeLayout()
  94. self.vmSideBySide = viewmode.ViewModeSideBySide()
  95. self.vmOverviewSmall = viewmode.ViewModeOverview(1)
  96. self.vmOverviewLarge = viewmode.ViewModeOverview(2)
  97. self.setViewMode(self.viewMode)
  98. self.makeConfDir()
  99. def makeConfDir(self):
  100. makeDir = not util.fileExists(misc.confPath)
  101. if makeDir:
  102. try:
  103. os.mkdir(misc.toPath(misc.confPath), 0755)
  104. except OSError, (errno, strerror):
  105. wx.MessageBox("Error creating configuration directory\n"
  106. "'%s': %s" % (misc.confPath, strerror),
  107. "Error", wx.OK, None)
  108. # set viewmode, the parameter is one of the VIEWMODE_ defines.
  109. def setViewMode(self, viewMode):
  110. self.viewMode = viewMode
  111. if viewMode == VIEWMODE_DRAFT:
  112. self.vm = self.vmDraft
  113. elif viewMode == VIEWMODE_LAYOUT:
  114. self.vm = self.vmLayout
  115. elif viewMode == VIEWMODE_SIDE_BY_SIDE:
  116. self.vm = self.vmSideBySide
  117. elif viewMode == VIEWMODE_OVERVIEW_SMALL:
  118. self.vm = self.vmOverviewSmall
  119. else:
  120. self.vm = self.vmOverviewLarge
  121. # load from string 's'. does not throw any exceptions and silently
  122. # ignores any errors.
  123. def load(self, s):
  124. self.cvars.load(self.cvars.makeVals(s), "", self)
  125. self.mru.items = self.files
  126. # save to a string and return that.
  127. def save(self):
  128. self.files = self.mru.items
  129. return self.cvars.save("", self)
  130. # save global spell checker dictionary to disk
  131. def saveScDict(self):
  132. util.writeToFile(self.scDictFilename, self.scDict.save(), mainFrame)
  133. class MyPanel(wx.Panel):
  134. def __init__(self, parent, id):
  135. wx.Panel.__init__(
  136. self, parent, id,
  137. # wxMSW/Windows does not seem to support
  138. # wx.NO_BORDER, which sucks
  139. style = wx.WANTS_CHARS | wx.NO_BORDER)
  140. hsizer = wx.BoxSizer(wx.HORIZONTAL)
  141. self.scrollBar = wx.ScrollBar(self, -1, style = wx.SB_VERTICAL)
  142. self.ctrl = MyCtrl(self, -1)
  143. hsizer.Add(self.ctrl, 1, wx.EXPAND)
  144. hsizer.Add(self.scrollBar, 0, wx.EXPAND)
  145. wx.EVT_COMMAND_SCROLL(self, self.scrollBar.GetId(),
  146. self.ctrl.OnScroll)
  147. wx.EVT_SET_FOCUS(self.scrollBar, self.OnScrollbarFocus)
  148. self.SetSizer(hsizer)
  149. # we never want the scrollbar to get the keyboard focus, pass it on to
  150. # the main widget
  151. def OnScrollbarFocus(self, event):
  152. self.ctrl.SetFocus()
  153. class MyCtrl(wx.Control):
  154. def __init__(self, parent, id):
  155. style = wx.WANTS_CHARS | wx.FULL_REPAINT_ON_RESIZE | wx.NO_BORDER
  156. wx.Control.__init__(self, parent, id, style = style)
  157. self.panel = parent
  158. wx.EVT_SIZE(self, self.OnSize)
  159. wx.EVT_PAINT(self, self.OnPaint)
  160. wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
  161. wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
  162. wx.EVT_LEFT_UP(self, self.OnLeftUp)
  163. wx.EVT_LEFT_DCLICK(self, self.OnLeftDown)
  164. wx.EVT_RIGHT_DOWN(self, self.OnRightDown)
  165. wx.EVT_MOTION(self, self.OnMotion)
  166. wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel)
  167. wx.EVT_CHAR(self, self.OnKeyChar)
  168. self.createEmptySp()
  169. self.updateScreen(redraw = False)
  170. def OnChangeType(self, event):
  171. cs = screenplay.CommandState()
  172. lt = idToLTMap[event.GetId()]
  173. self.sp.convertTypeTo(lt, True)
  174. self.sp.cmdPost(cs)
  175. if cs.needsVisifying:
  176. self.makeLineVisible(self.sp.line)
  177. self.updateScreen()
  178. def clearVars(self):
  179. self.mouseSelectActive = False
  180. # find dialog stored settings
  181. self.findDlgFindText = ""
  182. self.findDlgReplaceText = ""
  183. self.findDlgMatchWholeWord= False
  184. self.findDlgMatchCase = False
  185. self.findDlgDirUp = False
  186. self.findDlgUseExtra = False
  187. self.findDlgElements = None
  188. def createEmptySp(self):
  189. self.clearVars()
  190. self.sp = screenplay.Screenplay(cfgGl)
  191. self.sp.titles.addDefaults()
  192. self.sp.headers.addDefaults()
  193. self.setFile(None)
  194. self.refreshCache()
  195. # update stuff that depends on configuration / view mode etc.
  196. def refreshCache(self):
  197. self.chX = util.getTextWidth(" ", pml.COURIER, self.sp.cfg.fontSize)
  198. self.chY = util.getTextHeight(self.sp.cfg.fontSize)
  199. self.pageW = gd.vm.getPageWidth(self)
  200. # conversion factor from mm to pixels
  201. self.mm2p = self.pageW / self.sp.cfg.paperWidth
  202. # page width and height on screen, in pixels
  203. self.pageW = int(self.pageW)
  204. self.pageH = int(self.mm2p * self.sp.cfg.paperHeight)
  205. def getCfgGui(self):
  206. return cfgGui
  207. def loadFile(self, fileName):
  208. s = util.loadFile(fileName, mainFrame)
  209. if s == None:
  210. return
  211. try:
  212. (sp, msg) = screenplay.Screenplay.load(s, cfgGl)
  213. except TrelbyError, e:
  214. wx.MessageBox("Error loading file:\n\n%s" % e, "Error",
  215. wx.OK, mainFrame)
  216. return
  217. if msg:
  218. misc.showText(mainFrame, msg, "Warning")
  219. self.clearVars()
  220. self.sp = sp
  221. self.setFile(fileName)
  222. self.refreshCache()
  223. # saved cursor position might be anywhere, so we can't just
  224. # display the first page
  225. self.makeLineVisible(self.sp.line)
  226. # save script to given filename. returns True on success.
  227. def saveFile(self, fileName):
  228. fileName = util.ensureEndsIn(fileName, ".trelby")
  229. if util.writeToFile(fileName, self.sp.save(), mainFrame):
  230. self.setFile(fileName)
  231. self.sp.markChanged(False)
  232. gd.mru.add(fileName)
  233. return True
  234. else:
  235. return False
  236. def importFile(self, fileName):
  237. if fileName.endswith("fdx"):
  238. lines = myimport.importFDX(fileName, mainFrame)
  239. elif fileName.endswith("celtx"):
  240. lines = myimport.importCeltx(fileName, mainFrame)
  241. elif fileName.endswith("astx"):
  242. lines = myimport.importAstx(fileName, mainFrame)
  243. elif fileName.endswith("fountain"):
  244. lines = myimport.importFountain(fileName, mainFrame)
  245. elif fileName.endswith("fadein"):
  246. lines = myimport.importFadein(fileName, mainFrame)
  247. else:
  248. lines = myimport.importTextFile(fileName, mainFrame)
  249. if not lines:
  250. return
  251. self.createEmptySp()
  252. self.sp.lines = lines
  253. self.sp.reformatAll()
  254. self.sp.paginate()
  255. self.sp.markChanged(True)
  256. # generate exportable text from given screenplay, or None.
  257. def getExportText(self, sp):
  258. inf = []
  259. inf.append(misc.CheckBoxItem("Include page markers"))
  260. dlg = misc.CheckBoxDlg(mainFrame, "Output options", inf,
  261. "Options:", False)
  262. if dlg.ShowModal() != wx.ID_OK:
  263. dlg.Destroy()
  264. return None
  265. return sp.generateText(inf[0].selected)
  266. def getExportHtml(self, sp):
  267. inf = []
  268. inf.append(misc.CheckBoxItem("Include Notes"))
  269. dlg = misc.CheckBoxDlg(mainFrame, "Output options", inf,
  270. "Options:", False)
  271. if dlg.ShowModal() != wx.ID_OK:
  272. dlg.Destroy()
  273. return None
  274. return sp.generateHtml(inf[0].selected)
  275. def setFile(self, fileName):
  276. self.fileName = fileName
  277. if fileName:
  278. self.setDisplayName(os.path.basename(fileName))
  279. else:
  280. self.setDisplayName(u"untitled")
  281. self.setTabText()
  282. mainFrame.setTitle(self.fileNameDisplay)
  283. def setDisplayName(self, name):
  284. i = 1
  285. while 1:
  286. if i == 1:
  287. tmp = name
  288. else:
  289. tmp = name + "-%d" % i
  290. matched = False
  291. for c in mainFrame.getCtrls():
  292. if c == self:
  293. continue
  294. if c.fileNameDisplay == tmp:
  295. matched = True
  296. break
  297. if not matched:
  298. break
  299. i += 1
  300. self.fileNameDisplay = tmp
  301. def setTabText(self):
  302. mainFrame.setTabText(self.panel, self.fileNameDisplay)
  303. # texts = gd.vm.getScreen(self, False)[0], or None, in which case it's
  304. # called in this function.
  305. def isLineVisible(self, line, texts = None):
  306. if texts == None:
  307. texts = gd.vm.getScreen(self, False)[0]
  308. # paranoia never hurts
  309. if len(texts) == 0:
  310. return False
  311. return (line >= texts[0].line) and (line <= texts[-1].line)
  312. def makeLineVisible(self, line, direction = config.SCROLL_CENTER):
  313. texts = gd.vm.getScreen(self, False)[0]
  314. if self.isLineVisible(line, texts):
  315. return
  316. gd.vm.makeLineVisible(self, line, texts, direction)
  317. def adjustScrollBar(self):
  318. height = self.GetClientSize().height
  319. # rough approximation of how many lines fit onto the screen.
  320. # accuracy is not that important for this, so we don't even care
  321. # about draft / layout mode differences.
  322. approx = int(((height / self.mm2p) / self.chY) / 1.3)
  323. self.panel.scrollBar.SetScrollbar(self.sp.getTopLine(), approx,
  324. len(self.sp.lines) + approx - 1, approx)
  325. def clearAutoComp(self):
  326. if self.sp.clearAutoComp():
  327. self.Refresh(False)
  328. # returns true if there are no contents at all and we're not
  329. # attached to any file
  330. def isUntouched(self):
  331. if self.fileName or (len(self.sp.lines) > 1) or \
  332. (len(self.sp.lines[0].text) > 0):
  333. return False
  334. else:
  335. return True
  336. def updateScreen(self, redraw = True, setCommon = True):
  337. self.adjustScrollBar()
  338. if setCommon:
  339. self.updateCommon()
  340. if redraw:
  341. self.Refresh(False)
  342. # update GUI elements shared by all scripts, like statusbar etc
  343. def updateCommon(self):
  344. cur = cfgGl.getType(self.sp.lines[self.sp.line].lt)
  345. if self.sp.tabMakesNew():
  346. tabNext = "%s" % cfgGl.getType(cur.newTypeTab).ti.name
  347. else:
  348. tabNext = "%s" % cfgGl.getType(cur.nextTypeTab).ti.name
  349. enterNext = cfgGl.getType(cur.newTypeEnter).ti.name
  350. page = self.sp.line2page(self.sp.line)
  351. pageCnt = self.sp.line2page(len(self.sp.lines) - 1)
  352. mainFrame.statusCtrl.SetValues(page, pageCnt, cur.ti.name, tabNext, enterNext)
  353. canUndo = self.sp.canUndo()
  354. canRedo = self.sp.canRedo()
  355. mainFrame.menuBar.Enable(ID_EDIT_UNDO, canUndo)
  356. mainFrame.menuBar.Enable(ID_EDIT_REDO, canRedo)
  357. mainFrame.toolBar.EnableTool(ID_EDIT_UNDO, canUndo)
  358. mainFrame.toolBar.EnableTool(ID_EDIT_REDO, canRedo)
  359. # apply per-script config
  360. def applyCfg(self, newCfg):
  361. self.sp.applyCfg(newCfg)
  362. self.refreshCache()
  363. self.makeLineVisible(self.sp.line)
  364. self.updateScreen()
  365. # apply global config
  366. def applyGlobalCfg(self, newCfgGl, writeCfg = True):
  367. global cfgGl
  368. oldCfgGl = cfgGl
  369. cfgGl = copy.deepcopy(newCfgGl)
  370. # if user has ventured from the old default directory, keep it as
  371. # the current one, otherwise set the new default as current.
  372. if misc.scriptDir == oldCfgGl.scriptDir:
  373. misc.scriptDir = cfgGl.scriptDir
  374. cfgGl.recalc()
  375. refreshGuiConfig()
  376. mainFrame.updateKbdCommands()
  377. for c in mainFrame.getCtrls():
  378. c.sp.cfgGl = cfgGl
  379. c.refreshCache()
  380. c.makeLineVisible(c.sp.line)
  381. c.adjustScrollBar()
  382. self.updateScreen()
  383. # in case tab colors have been changed
  384. mainFrame.tabCtrl.Refresh(False)
  385. mainFrame.statusCtrl.Refresh(False)
  386. mainFrame.noFSBtn.Refresh(False)
  387. mainFrame.toolBar.SetBackgroundColour(cfgGui.tabBarBgColor)
  388. if writeCfg:
  389. util.writeToFile(gd.confFilename, cfgGl.save(), mainFrame)
  390. mainFrame.checkFonts()
  391. def applyHeaders(self, newHeaders):
  392. self.sp.headers = newHeaders
  393. self.sp.markChanged()
  394. self.OnPaginate()
  395. # return an exportable, paginated Screenplay object, or None if for
  396. # some reason that's not possible / wanted. 'action' is the name of
  397. # the action, e.g. "export" or "print", that'll be done to the script,
  398. # and is used in dialogue with the user if needed.
  399. def getExportable(self, action):
  400. if cfgGl.checkOnExport:
  401. line = self.sp.findError(0)[0]
  402. if line != -1:
  403. if wx.MessageBox(
  404. "The script seems to contain errors.\n"
  405. "Are you sure you want to %s it?" % action, "Confirm",
  406. wx.YES_NO | wx.NO_DEFAULT, mainFrame) == wx.NO:
  407. return None
  408. sp = self.sp
  409. if sp.cfg.pdfRemoveNotes:
  410. sp = copy.deepcopy(self.sp)
  411. sp.removeElementTypes({screenplay.NOTE : None}, False)
  412. sp.paginate()
  413. return sp
  414. def OnEraseBackground(self, event):
  415. pass
  416. def OnSize(self, event):
  417. if misc.doDblBuf:
  418. size = self.GetClientSize()
  419. sb = wx.EmptyBitmap(size.width, size.height)
  420. old = getattr(self.__class__, "screenBuf", None)
  421. if (old == None) or (old.GetDepth() != sb.GetDepth()) or \
  422. (old.GetHeight() != sb.GetHeight()) or \
  423. (old.GetWidth() != sb.GetWidth()):
  424. self.__class__.screenBuf = sb
  425. self.makeLineVisible(self.sp.line)
  426. def OnLeftDown(self, event, mark = False):
  427. if not self.mouseSelectActive:
  428. self.sp.clearMark()
  429. self.updateScreen()
  430. pos = event.GetPosition()
  431. line, col = gd.vm.pos2linecol(self, pos.x, pos.y)
  432. self.mouseSelectActive = True
  433. if line is not None:
  434. self.sp.gotoPos(line, col, mark)
  435. self.updateScreen()
  436. def OnLeftUp(self, event):
  437. self.mouseSelectActive = False
  438. # to avoid phantom selections (Windows sends some strange events
  439. # sometimes), check if anything worthwhile is actually selected.
  440. cd = self.sp.getSelectedAsCD(False)
  441. if not cd or ((len(cd.lines) == 1) and (len(cd.lines[0].text) < 2)):
  442. self.sp.clearMark()
  443. def OnMotion(self, event):
  444. if event.LeftIsDown():
  445. self.OnLeftDown(event, mark = True)
  446. def OnRightDown(self, event):
  447. # No popup in the overview modes.
  448. if gd.viewMode in (VIEWMODE_OVERVIEW_SMALL, VIEWMODE_OVERVIEW_LARGE):
  449. return
  450. pos = event.GetPosition()
  451. line, col = gd.vm.pos2linecol(self, pos.x, pos.y)
  452. if self.sp.mark:
  453. m = mainFrame.rightClickMenuWithCut
  454. else:
  455. m = mainFrame.rightClickMenu
  456. if line is not None and (line != self.sp.line):
  457. self.sp.gotoPos(line, col, False)
  458. self.updateScreen()
  459. self.PopupMenu(m)
  460. def OnMouseWheel(self, event):
  461. if event.GetWheelRotation() > 0:
  462. delta = -cfgGl.mouseWheelLines
  463. else:
  464. delta = cfgGl.mouseWheelLines
  465. self.sp.setTopLine(self.sp.getTopLine() + delta)
  466. self.updateScreen()
  467. def OnScroll(self, event):
  468. pos = self.panel.scrollBar.GetThumbPosition()
  469. self.sp.setTopLine(pos)
  470. self.sp.clearAutoComp()
  471. self.updateScreen()
  472. def OnPaginate(self):
  473. self.sp.paginate()
  474. self.makeLineVisible(self.sp.line)
  475. self.updateScreen()
  476. def OnAutoCompletionDlg(self):
  477. dlg = autocompletiondlg.AutoCompletionDlg(mainFrame,
  478. copy.deepcopy(self.sp.autoCompletion))
  479. if dlg.ShowModal() == wx.ID_OK:
  480. self.sp.autoCompletion = dlg.autoCompletion
  481. self.sp.markChanged()
  482. dlg.Destroy()
  483. def OnTitlesDlg(self):
  484. dlg = titlesdlg.TitlesDlg(mainFrame, copy.deepcopy(self.sp.titles),
  485. self.sp.cfg, cfgGl)
  486. if dlg.ShowModal() == wx.ID_OK:
  487. self.sp.titles = dlg.titles
  488. self.sp.markChanged()
  489. dlg.Destroy()
  490. def OnHeadersDlg(self):
  491. dlg = headersdlg.HeadersDlg(mainFrame,
  492. copy.deepcopy(self.sp.headers), self.sp.cfg, cfgGl,
  493. self.applyHeaders)
  494. if dlg.ShowModal() == wx.ID_OK:
  495. self.applyHeaders(dlg.headers)
  496. dlg.Destroy()
  497. def OnLocationsDlg(self):
  498. dlg = locationsdlg.LocationsDlg(mainFrame, copy.deepcopy(self.sp))
  499. if dlg.ShowModal() == wx.ID_OK:
  500. self.sp.locations = dlg.sp.locations
  501. self.sp.markChanged()
  502. dlg.Destroy()
  503. def OnSpellCheckerScriptDictionaryDlg(self):
  504. dlg = spellcheckcfgdlg.SCDictDlg(mainFrame,
  505. copy.deepcopy(self.sp.scDict), False)
  506. if dlg.ShowModal() == wx.ID_OK:
  507. self.sp.scDict = dlg.scDict
  508. self.sp.markChanged()
  509. dlg.Destroy()
  510. def OnWatermark(self):
  511. dlg = watermarkdlg.WatermarkDlg(
  512. mainFrame, self.sp, self.fileNameDisplay.replace(".trelby", ""))
  513. dlg.ShowModal()
  514. dlg.Destroy()
  515. def OnReportDialogueChart(self):
  516. self.sp.paginate()
  517. dialoguechart.genDialogueChart(mainFrame, self.sp)
  518. def OnReportCharacter(self):
  519. self.sp.paginate()
  520. characterreport.genCharacterReport(mainFrame, self.sp)
  521. def OnReportLocation(self):
  522. self.sp.paginate()
  523. locationreport.genLocationReport(mainFrame, self.sp)
  524. def OnReportScene(self):
  525. self.sp.paginate()
  526. scenereport.genSceneReport(mainFrame, self.sp)
  527. def OnReportScript(self):
  528. self.sp.paginate()
  529. scriptreport.genScriptReport(mainFrame, self.sp)
  530. def OnCompareScripts(self):
  531. if mainFrame.tabCtrl.getPageCount() < 2:
  532. wx.MessageBox("You need at least two scripts open to"
  533. " compare them.", "Error", wx.OK, mainFrame)
  534. return
  535. items = []
  536. for c in mainFrame.getCtrls():
  537. items.append(c.fileNameDisplay)
  538. dlg = misc.ScriptChooserDlg(mainFrame, items)
  539. sel1 = -1
  540. sel2 = -1
  541. if dlg.ShowModal() == wx.ID_OK:
  542. sel1 = dlg.sel1
  543. sel2 = dlg.sel2
  544. force = dlg.forceSameCfg
  545. dlg.Destroy()
  546. if sel1 == -1:
  547. return
  548. if sel1 == sel2:
  549. wx.MessageBox("You can't compare a script to itself.", "Error",
  550. wx.OK, mainFrame)
  551. return
  552. c1 = mainFrame.tabCtrl.getPage(sel1).ctrl
  553. c2 = mainFrame.tabCtrl.getPage(sel2).ctrl
  554. sp1 = c1.getExportable("compare")
  555. sp2 = c2.getExportable("compare")
  556. if not sp1 or not sp2:
  557. return
  558. if force:
  559. sp2 = copy.deepcopy(sp2)
  560. sp2.cfg = copy.deepcopy(sp1.cfg)
  561. sp2.reformatAll()
  562. sp2.paginate()
  563. s = sp1.compareScripts(sp2)
  564. if s:
  565. gutil.showTempPDF(s, cfgGl, mainFrame)
  566. else:
  567. wx.MessageBox("The scripts are identical.", "Results", wx.OK,
  568. mainFrame)
  569. def canBeClosed(self):
  570. if self.sp.isModified():
  571. if wx.MessageBox("The script has been modified. Are you sure\n"
  572. "you want to discard the changes?", "Confirm",
  573. wx.YES_NO | wx.NO_DEFAULT, mainFrame) == wx.NO:
  574. return False
  575. return True
  576. # page up (dir == -1) or page down (dir == 1) was pressed, handle it.
  577. # cs = CommandState.
  578. def pageCmd(self, cs, dir):
  579. if self.sp.acItems:
  580. cs.doAutoComp = cs.AC_KEEP
  581. self.sp.pageScrollAutoComp(dir)
  582. return
  583. texts, dpages = gd.vm.getScreen(self, False)
  584. # if user has scrolled with scrollbar so that cursor isn't seen,
  585. # just make cursor visible and don't move
  586. if not self.isLineVisible(self.sp.line, texts):
  587. gd.vm.makeLineVisible(self, self.sp.line, texts)
  588. cs.needsVisifying = False
  589. return
  590. self.sp.maybeMark(cs.mark)
  591. gd.vm.pageCmd(self, cs, dir, texts, dpages)
  592. def OnRevertScript(self):
  593. if self.fileName:
  594. if not self.canBeClosed():
  595. return
  596. self.loadFile(self.fileName)
  597. self.updateScreen()
  598. def OnUndo(self):
  599. self.sp.cmd("undo")
  600. self.sp.paginate()
  601. self.makeLineVisible(self.sp.line)
  602. self.updateScreen()
  603. def OnRedo(self):
  604. self.sp.cmd("redo")
  605. self.sp.paginate()
  606. self.makeLineVisible(self.sp.line)
  607. self.updateScreen()
  608. # returns True if something was deleted
  609. def OnCut(self, doUpdate = True, doDelete = True, copyToClip = True):
  610. marked = self.sp.getMarkedLines()
  611. if not marked:
  612. return False
  613. cd = self.sp.getSelectedAsCD(doDelete)
  614. if copyToClip:
  615. mainFrame.clipboard = cd
  616. if doUpdate:
  617. self.makeLineVisible(self.sp.line)
  618. self.updateScreen()
  619. return doDelete
  620. def OnCopy(self):
  621. self.OnCut(doDelete = False)
  622. def OnCopySystem(self, formatted = False):
  623. cd = self.sp.getSelectedAsCD(False)
  624. if not cd:
  625. return
  626. tmpSp = screenplay.Screenplay(cfgGl)
  627. tmpSp.lines = cd.lines
  628. if formatted:
  629. # have to call paginate, otherwise generateText will not
  630. # process all the text
  631. tmpSp.paginate()
  632. s = tmpSp.generateText(False)
  633. else:
  634. s = util.String()
  635. for ln in tmpSp.lines:
  636. txt = ln.text
  637. if tmpSp.cfg.getType(ln.lt).export.isCaps:
  638. txt = util.upper(txt)
  639. s += txt + config.lb2str(ln.lb)
  640. s = str(s).replace("\n", os.linesep)
  641. if wx.TheClipboard.Open():
  642. wx.TheClipboard.UsePrimarySelection(False)
  643. wx.TheClipboard.Clear()
  644. wx.TheClipboard.AddData(wx.TextDataObject(s))
  645. wx.TheClipboard.Flush()
  646. wx.TheClipboard.Close()
  647. def OnPaste(self, clines = None):
  648. if not clines:
  649. cd = mainFrame.clipboard
  650. if not cd:
  651. return
  652. clines = cd.lines
  653. self.sp.paste(clines)
  654. self.makeLineVisible(self.sp.line)
  655. self.updateScreen()
  656. def OnPasteSystemCb(self):
  657. s = ""
  658. if wx.TheClipboard.Open():
  659. wx.TheClipboard.UsePrimarySelection(False)
  660. df = wx.DataFormat(wx.DF_TEXT)
  661. if wx.TheClipboard.IsSupported(df):
  662. data = wx.TextDataObject()
  663. wx.TheClipboard.GetData(data)
  664. s = util.cleanInput(data.GetText())
  665. wx.TheClipboard.Close()
  666. s = util.fixNL(s)
  667. if len(s) == 0:
  668. return
  669. inLines = s.split("\n")
  670. # shouldn't be possible, but...
  671. if len(inLines) == 0:
  672. return
  673. lines = []
  674. for s in inLines:
  675. if s:
  676. lines.append(screenplay.Line(screenplay.LB_LAST,
  677. screenplay.ACTION, s))
  678. self.OnPaste(lines)
  679. def OnSelectScene(self):
  680. self.sp.cmd("selectScene")
  681. self.makeLineVisible(self.sp.line)
  682. self.updateScreen()
  683. def OnSelectAll(self):
  684. self.sp.cmd("selectAll")
  685. self.makeLineVisible(self.sp.line)
  686. self.updateScreen()
  687. def OnGotoScene(self):
  688. self.sp.paginate()
  689. self.clearAutoComp()
  690. scenes = self.sp.getSceneLocations()
  691. def validateFunc(s):
  692. if s in [x[0] for x in scenes]:
  693. return ""
  694. else:
  695. return "Invalid scene number."
  696. dlg = misc.TextInputDlg(mainFrame, "Enter scene number (%s - %s):" %\
  697. (scenes[0][0], scenes[-1][0]), "Goto scene", validateFunc)
  698. if dlg.ShowModal() == wx.ID_OK:
  699. for it in scenes:
  700. if it[0] == dlg.input:
  701. self.sp.line = it[1]
  702. self.sp.column = 0
  703. break
  704. # we need to refresh the screen in all cases because pagination
  705. # might have changed
  706. self.makeLineVisible(self.sp.line)
  707. self.updateScreen()
  708. def OnGotoPage(self):
  709. self.sp.paginate()
  710. self.clearAutoComp()
  711. pages = self.sp.getPageNumbers()
  712. def validateFunc(s):
  713. if s in pages:
  714. return ""
  715. else:
  716. return "Invalid page number."
  717. dlg = misc.TextInputDlg(mainFrame, "Enter page number (%s - %s):" %\
  718. (pages[0], pages[-1]), "Goto page", validateFunc)
  719. if dlg.ShowModal() == wx.ID_OK:
  720. page = int(dlg.input)
  721. self.sp.line = self.sp.page2lines(page)[0]
  722. self.sp.column = 0
  723. # we need to refresh the screen in all cases because pagination
  724. # might have changed
  725. self.makeLineVisible(self.sp.line)
  726. self.updateScreen()
  727. def OnInsertNbsp(self):
  728. self.OnKeyChar(util.MyKeyEvent(160))
  729. def OnFindNextError(self):
  730. self.clearAutoComp()
  731. line, msg = self.sp.findError(self.sp.line)
  732. if line != -1:
  733. self.sp.line = line
  734. self.sp.column = 0
  735. self.makeLineVisible(self.sp.line)
  736. self.updateScreen()
  737. else:
  738. msg = "No errors found."
  739. wx.MessageBox(msg, "Results", wx.OK, mainFrame)
  740. def OnFind(self):
  741. self.sp.clearMark()
  742. self.clearAutoComp()
  743. self.updateScreen()
  744. dlg = finddlg.FindDlg(mainFrame, self)
  745. dlg.ShowModal()
  746. dlg.saveState()
  747. dlg.Destroy()
  748. self.sp.clearMark()
  749. self.makeLineVisible(self.sp.line)
  750. self.updateScreen()
  751. def OnSpellCheckerDlg(self):
  752. self.sp.clearMark()
  753. self.clearAutoComp()
  754. wasAtStart = self.sp.line == 0
  755. wx.BeginBusyCursor()
  756. if not spellcheck.loadDict(mainFrame):
  757. wx.EndBusyCursor()
  758. return
  759. sc = spellcheck.SpellChecker(self.sp, gd.scDict)
  760. found = sc.findNext()
  761. wx.EndBusyCursor()
  762. if not found:
  763. s = ""
  764. if not wasAtStart:
  765. s = "\n\n(Starting position was not at\n"\
  766. "the beginning of the script.)"
  767. wx.MessageBox("Spell checker found no errors." + s, "Results",
  768. wx.OK, mainFrame)
  769. return
  770. dlg = spellcheckdlg.SpellCheckDlg(mainFrame, self, sc, gd.scDict)
  771. dlg.ShowModal()
  772. if dlg.changedGlobalDict:
  773. gd.saveScDict()
  774. dlg.Destroy()
  775. self.sp.clearMark()
  776. self.makeLineVisible(self.sp.line)
  777. self.updateScreen()
  778. def OnDeleteElements(self):
  779. # even though Screenplay.removeElementTypes does this as well, do
  780. # it here so that screen is cleared from the auto-comp box before
  781. # we open the dialog
  782. self.clearAutoComp()
  783. types = []
  784. for t in config.getTIs():
  785. types.append(misc.CheckBoxItem(t.name, False, t.lt))
  786. dlg = misc.CheckBoxDlg(mainFrame, "Delete elements", types,
  787. "Element types to delete:", True)
  788. ok = False
  789. if dlg.ShowModal() == wx.ID_OK:
  790. ok = True
  791. tdict = misc.CheckBoxItem.getClientData(types)
  792. dlg.Destroy()
  793. if not ok or (len(tdict) == 0):
  794. return
  795. self.sp.removeElementTypes(tdict, True)
  796. self.sp.paginate()
  797. self.makeLineVisible(self.sp.line)
  798. self.updateScreen()
  799. def OnSave(self):
  800. if self.fileName:
  801. self.saveFile(self.fileName)
  802. else:
  803. self.OnSaveScriptAs()
  804. def OnSaveScriptAs(self):
  805. if self.fileName:
  806. dDir = os.path.dirname(self.fileName)
  807. dFile = os.path.basename(self.fileName)
  808. else:
  809. dDir = misc.scriptDir
  810. dFile = u""
  811. dlg = wx.FileDialog(mainFrame, "Filename to save as",
  812. defaultDir = dDir,
  813. defaultFile = dFile,
  814. wildcard = "Trelby files (*.trelby)|*.trelby|All files|*",
  815. style = wx.SAVE | wx.OVERWRITE_PROMPT)
  816. if dlg.ShowModal() == wx.ID_OK:
  817. self.saveFile(dlg.GetPath())
  818. dlg.Destroy()
  819. def OnExportScript(self):
  820. sp = self.getExportable("export")
  821. if not sp:
  822. return
  823. dlg = wx.FileDialog(mainFrame, "Filename to export as",
  824. misc.scriptDir,
  825. wildcard = "PDF|*.pdf|"
  826. "RTF|*.rtf|"
  827. "Final Draft XML|*.fdx|"
  828. "HTML|*.html|"
  829. "Fountain|*.fountain|"
  830. "Formatted text|*.txt",
  831. style = wx.SAVE | wx.OVERWRITE_PROMPT)
  832. if dlg.ShowModal() == wx.ID_OK:
  833. misc.scriptDir = dlg.GetDirectory()
  834. choice = dlg.GetFilterIndex()
  835. if choice == 0:
  836. data = sp.generatePDF(True)
  837. suffix = ".pdf"
  838. elif choice == 1:
  839. data = sp.generateRTF()
  840. suffix = ".rtf"
  841. elif choice == 2:
  842. data = sp.generateFDX()
  843. suffix = ".fdx"
  844. elif choice == 3:
  845. data = self.getExportHtml(sp)
  846. suffix = ".html"
  847. elif choice == 4:
  848. data = sp.generateFountain()
  849. suffix = ".fountain"
  850. else:
  851. data = self.getExportText(sp)
  852. suffix = ".txt"
  853. fileName = util.ensureEndsIn(dlg.GetPath(), suffix)
  854. if data:
  855. util.writeToFile(fileName, data, mainFrame)
  856. dlg.Destroy()
  857. def OnPrint(self):
  858. sp = self.getExportable("print")
  859. if not sp:
  860. return
  861. s = sp.generatePDF(False)
  862. gutil.showTempPDF(s, cfgGl, mainFrame)
  863. def OnSettings(self):
  864. dlg = cfgdlg.CfgDlg(mainFrame, copy.deepcopy(cfgGl),
  865. self.applyGlobalCfg, True)
  866. if dlg.ShowModal() == wx.ID_OK:
  867. self.applyGlobalCfg(dlg.cfg)
  868. dlg.Destroy()
  869. def OnScriptSettings(self):
  870. dlg = cfgdlg.CfgDlg(mainFrame, copy.deepcopy(self.sp.cfg),
  871. self.applyCfg, False)
  872. if dlg.ShowModal() == wx.ID_OK:
  873. self.applyCfg(dlg.cfg)
  874. dlg.Destroy()
  875. def cmdAbort(self, cs):
  876. self.sp.abortCmd(cs)
  877. def cmdChangeToAction(self, cs):
  878. self.sp.toActionCmd(cs)
  879. def cmdChangeToCharacter(self, cs):
  880. self.sp.toCharacterCmd(cs)
  881. def cmdChangeToDialogue(self, cs):
  882. self.sp.toDialogueCmd(cs)
  883. def cmdChangeToNote(self, cs):
  884. self.sp.toNoteCmd(cs)
  885. def cmdChangeToParenthetical(self, cs):
  886. self.sp.toParenCmd(cs)
  887. def cmdChangeToScene(self, cs):
  888. self.sp.toSceneCmd(cs)
  889. def cmdChangeToShot(self, cs):
  890. self.sp.toShotCmd(cs)
  891. def cmdChangeToActBreak(self,cs):
  892. self.sp.toActBreakCmd(cs)
  893. def cmdChangeToTransition(self, cs):
  894. self.sp.toTransitionCmd(cs)
  895. def cmdDelete(self, cs):
  896. if not self.sp.mark:
  897. self.sp.deleteForwardCmd(cs)
  898. else:
  899. self.OnCut(doUpdate = False, copyToClip = False)
  900. def cmdDeleteBackward(self, cs):
  901. if not self.sp.mark:
  902. self.sp.deleteBackwardCmd(cs)
  903. else:
  904. self.OnCut(doUpdate = False, copyToClip = False)
  905. def cmdForcedLineBreak(self, cs):
  906. self.sp.insertForcedLineBreakCmd(cs)
  907. def cmdMoveDown(self, cs):
  908. self.sp.moveDownCmd(cs)
  909. def cmdMoveEndOfLine(self, cs):
  910. self.sp.moveLineEndCmd(cs)
  911. def cmdMoveEndOfScript(self, cs):
  912. self.sp.moveEndCmd(cs)
  913. def cmdMoveLeft(self, cs):
  914. self.sp.moveLeftCmd(cs)
  915. def cmdMovePageDown(self, cs):
  916. self.pageCmd(cs, 1)
  917. def cmdMovePageUp(self, cs):
  918. self.pageCmd(cs, -1)
  919. def cmdMoveRight(self, cs):
  920. self.sp.moveRightCmd(cs)
  921. def cmdMoveSceneDown(self, cs):
  922. self.sp.moveSceneDownCmd(cs)
  923. def cmdMoveSceneUp(self, cs):
  924. self.sp.moveSceneUpCmd(cs)
  925. def cmdMoveStartOfLine(self, cs):
  926. self.sp.moveLineStartCmd(cs)
  927. def cmdMoveStartOfScript(self, cs):
  928. self.sp.moveStartCmd(cs)
  929. def cmdMoveUp(self, cs):
  930. self.sp.moveUpCmd(cs)
  931. def cmdNewElement(self, cs):
  932. self.sp.splitElementCmd(cs)
  933. def cmdSetMark(self, cs):
  934. self.sp.setMarkCmd(cs)
  935. def cmdTab(self, cs):
  936. self.sp.tabCmd(cs)
  937. def cmdTabPrev(self, cs):
  938. self.sp.toPrevTypeTabCmd(cs)
  939. def cmdSpeedTest(self, cs):
  940. import undo
  941. self.speedTestUndo = []
  942. def testUndoFullCopy():
  943. u = undo.FullCopy(self.sp)
  944. u.setAfter(self.sp)
  945. self.speedTestUndo.append(u)
  946. def testReformatAll():
  947. self.sp.reformatAll()
  948. def testPaginate():
  949. self.sp.paginate()
  950. def testUpdateScreen():
  951. self.updateScreen()
  952. self.Update()
  953. def testAddRemoveChar():
  954. self.OnKeyChar(util.MyKeyEvent(ord("a")))
  955. self.OnKeyChar(util.MyKeyEvent(wx.WXK_BACK))
  956. def testDeepcopy():
  957. copy.deepcopy(self.sp)
  958. # contains (name, func) tuples
  959. tests = []
  960. for name, var in locals().iteritems():
  961. if callable(var):
  962. tests.append((name, var))
  963. tests.sort()
  964. count = 100
  965. print "-" * 20
  966. for name, func in tests:
  967. t = time.time()
  968. for i in xrange(count):
  969. func()
  970. t = time.time() - t
  971. print "%.5f seconds per %s" % (t / count, name)
  972. print "-" * 20
  973. # it's annoying having the program ask if you want to save after
  974. # running these tests, so pretend the script hasn't changed
  975. self.sp.markChanged(False)
  976. def cmdTest(self, cs):
  977. pass
  978. def OnKeyChar(self, ev):
  979. kc = ev.GetKeyCode()
  980. #print "kc: %d, ctrl/alt/shift: %d, %d, %d" %\
  981. # (kc, ev.ControlDown(), ev.AltDown(), ev.ShiftDown())
  982. cs = screenplay.CommandState()
  983. cs.mark = bool(ev.ShiftDown())
  984. scrollDirection = config.SCROLL_CENTER
  985. if not ev.ControlDown() and not ev.AltDown() and \
  986. util.isValidInputChar(kc):
  987. # WX2.6-FIXME: we should probably use GetUnicodeKey() (dunno
  988. # how to get around the isValidInputChar test in the preceding
  989. # line, need to test what GetUnicodeKey() returns on
  990. # non-input-character events)
  991. addChar = True
  992. # If there's something selected, either remove it, or clear selection.
  993. if self.sp.mark and cfgGl.overwriteSelectionOnInsert:
  994. if not self.OnCut(doUpdate = False, copyToClip = False):
  995. self.sp.clearMark()
  996. addChar = False
  997. if addChar:
  998. cs.char = chr(kc)
  999. if opts.isTest and (cs.char == "ĺ"):
  1000. self.loadFile(u"sample.trelby")
  1001. elif opts.isTest and (cs.char == "¤"):
  1002. self.cmdTest(cs)
  1003. elif opts.isTest and (cs.char == "˝"):
  1004. self.cmdSpeedTest(cs)
  1005. else:
  1006. self.sp.addCharCmd(cs)
  1007. else:
  1008. cmd = mainFrame.kbdCommands.get(util.Key(kc,
  1009. ev.ControlDown(), ev.AltDown(), ev.ShiftDown()).toInt())
  1010. if cmd:
  1011. scrollDirection = cmd.scrollDirection
  1012. if cmd.isMenu:
  1013. getattr(mainFrame, "On" + cmd.name)()
  1014. return
  1015. else:
  1016. getattr(self, "cmd" + cmd.name)(cs)
  1017. else:
  1018. ev.Skip()
  1019. return
  1020. self.sp.cmdPost(cs)
  1021. if cfgGl.paginateInterval > 0:
  1022. now = time.time()
  1023. if (now - self.sp.lastPaginated) >= cfgGl.paginateInterval:
  1024. self.sp.paginate()
  1025. cs.needsVisifying = True
  1026. if cs.needsVisifying:
  1027. self.makeLineVisible(self.sp.line, scrollDirection)
  1028. self.updateScreen()
  1029. def OnPaint(self, event):
  1030. #ldkjfldsj = util.TimerDev("paint")
  1031. ls = self.sp.lines
  1032. if misc.doDblBuf:
  1033. dc = wx.BufferedPaintDC(self, self.screenBuf)
  1034. else:
  1035. dc = wx.PaintDC(self)
  1036. size = self.GetClientSize()
  1037. marked = self.sp.getMarkedLines()
  1038. lineh = gd.vm.getLineHeight(self)
  1039. posX = -1
  1040. cursorY = -1
  1041. # auto-comp FontInfo
  1042. acFi = None
  1043. # key = font, value = ([text, ...], [(x, y), ...], [wx.Colour, ...])
  1044. texts = {}
  1045. # lists of underline-lines to draw, one for normal text and one
  1046. # for header texts. list objects are (x, y, width) tuples.
  1047. ulines = []
  1048. ulinesHdr = []
  1049. strings, dpages = gd.vm.getScreen(self, True, True)
  1050. dc.SetBrush(cfgGui.workspaceBrush)
  1051. dc.SetPen(cfgGui.workspacePen)
  1052. dc.DrawRectangle(0, 0, size.width, size.height)
  1053. dc.SetPen(cfgGui.tabBorderPen)
  1054. dc.DrawLine(0,0,0,size.height)
  1055. if not dpages:
  1056. # draft mode; draw an infinite page
  1057. lx = util.clamp((size.width - self.pageW) // 2, 0)
  1058. rx = lx + self.pageW
  1059. dc.SetBrush(cfgGui.textBgBrush)
  1060. dc.SetPen(cfgGui.textBgPen)
  1061. dc.DrawRectangle(lx, 5, self.pageW, size.height - 5)
  1062. dc.SetPen(cfgGui.pageBorderPen)
  1063. dc.DrawLine(lx, 5, lx, size.height)
  1064. dc.DrawLine(rx, 5, rx, size.height)
  1065. else:
  1066. dc.SetBrush(cfgGui.textBgBrush)
  1067. dc.SetPen(cfgGui.pageBorderPen)
  1068. for dp in dpages:
  1069. dc.DrawRectangle(dp.x1, dp.y1, dp.x2 - dp.x1 + 1,
  1070. dp.y2 - dp.y1 + 1)
  1071. dc.SetPen(cfgGui.pageShadowPen)
  1072. for dp in dpages:
  1073. # + 2 because DrawLine doesn't draw to end point but stops
  1074. # one pixel short...
  1075. dc.DrawLine(dp.x1 + 1, dp.y2 + 1, dp.x2 + 1, dp.y2 + 1)
  1076. dc.DrawLine(dp.x2 + 1, dp.y1 + 1, dp.x2 + 1, dp.y2 + 2)
  1077. for t in strings:
  1078. i = t.line
  1079. y = t.y
  1080. fi = t.fi
  1081. fx = fi.fx
  1082. if i != -1:
  1083. l = ls[i]
  1084. if l.lt == screenplay.NOTE:
  1085. dc.SetPen(cfgGui.notePen)
  1086. dc.SetBrush(cfgGui.noteBrush)
  1087. nx = t.x - 5
  1088. nw = self.sp.cfg.getType(l.lt).width * fx + 10
  1089. dc.DrawRectangle(nx, y, nw, lineh)
  1090. dc.SetPen(cfgGui.textPen)
  1091. util.drawLine(dc, nx - 1, y, 0, lineh)
  1092. util.drawLine(dc, nx + nw, y, 0, lineh)
  1093. if self.sp.isFirstLineOfElem(i):
  1094. util.drawLine(dc, nx - 1, y - 1, nw + 2, 0)
  1095. if self.sp.isLastLineOfElem(i):
  1096. util.drawLine(dc, nx - 1, y + lineh,
  1097. nw + 2, 0)
  1098. if marked and self.sp.isLineMarked(i, marked):
  1099. c1, c2 = self.sp.getMarkedColumns(i, marked)
  1100. dc.SetPen(cfgGui.selectedPen)
  1101. dc.SetBrush(cfgGui.selectedBrush)
  1102. dc.DrawRectangle(t.x + c1 * fx, y, (c2 - c1 + 1) * fx,
  1103. lineh)
  1104. if mainFrame.showFormatting:
  1105. dc.SetPen(cfgGui.bluePen)
  1106. util.drawLine(dc, t.x, y, 0, lineh)
  1107. extraIndent = 1 if self.sp.needsExtraParenIndent(i) else 0
  1108. util.drawLine(dc,
  1109. t.x + (self.sp.cfg.getType(l.lt).width - extraIndent) * fx,
  1110. y, 0, lineh)
  1111. dc.SetTextForeground(cfgGui.redColor)
  1112. dc.SetFont(cfgGui.fonts[pml.NORMAL].font)
  1113. dc.DrawText(config.lb2char(l.lb), t.x - 10, y)
  1114. if not dpages:
  1115. if cfgGl.pbi == config.PBI_REAL_AND_UNADJ:
  1116. if self.sp.line2pageNoAdjust(i) != \
  1117. self.sp.line2pageNoAdjust(i + 1):
  1118. dc.SetPen(cfgGui.pagebreakNoAdjustPen)
  1119. util.drawLine(dc, 0, y + lineh - 1,
  1120. size.width, 0)
  1121. if cfgGl.pbi in (config.PBI_REAL,
  1122. config.PBI_REAL_AND_UNADJ):
  1123. thisPage = self.sp.line2page(i)
  1124. if thisPage != self.sp.line2page(i + 1):
  1125. dc.SetPen(cfgGui.pagebreakPen)
  1126. util.drawLine(dc, 0, y + lineh - 1,
  1127. size.width, 0)
  1128. if i == self.sp.line:
  1129. posX = t.x
  1130. cursorY = y
  1131. acFi = fi
  1132. dc.SetPen(cfgGui.cursorPen)
  1133. dc.SetBrush(cfgGui.cursorBrush)
  1134. dc.DrawRectangle(t.x + self.sp.column * fx, y, fx, fi.fy)
  1135. if len(t.text) != 0:
  1136. tl = texts.get(fi.font)
  1137. if tl == None:
  1138. tl = ([], [], [])
  1139. texts[fi.font] = tl
  1140. tl[0].append(t.text)
  1141. tl[1].append((t.x, y))
  1142. if t.line != -1:
  1143. if cfgGl.useCustomElemColors:
  1144. tl[2].append(cfgGui.lt2textColor(ls[t.line].lt))
  1145. else:
  1146. tl[2].append(cfgGui.textColor)
  1147. else:
  1148. tl[2].append(cfgGui.textHdrColor)
  1149. if t.isUnderlined:
  1150. if t.line != -1:
  1151. uli = ulines
  1152. else:
  1153. uli = ulinesHdr
  1154. uli.append((t.x, y + lineh - 1,
  1155. len(t.text) * fx - 1))
  1156. if ulines:
  1157. dc.SetPen(cfgGui.textPen)
  1158. for ul in ulines:
  1159. util.drawLine(dc, ul[0], ul[1], ul[2], 0)
  1160. if ulinesHdr:
  1161. dc.SetPen(cfgGui.textHdrPen)
  1162. for ul in ulinesHdr:
  1163. util.drawLine(dc, ul[0], ul[1], ul[2], 0)
  1164. for tl in texts.iteritems():
  1165. gd.vm.drawTexts(self, dc, tl)
  1166. if self.sp.acItems and (cursorY > 0):
  1167. self.drawAutoComp(dc, posX, cursorY, acFi)
  1168. def drawAutoComp(self, dc, posX, cursorY, fi):
  1169. ac = self.sp.acItems
  1170. asel = self.sp.acSel
  1171. offset = 5
  1172. selBleed = 2
  1173. # scroll bar width
  1174. sbw = 10
  1175. size = self.GetClientSize()
  1176. dc.SetFont(fi.font)
  1177. show = min(self.sp.acMax, len(ac))
  1178. doSbw = show < len(ac)
  1179. startPos = (asel // show) * show
  1180. endPos = min(startPos + show, len(ac))
  1181. if endPos == len(ac):
  1182. startPos = max(0, endPos - show)
  1183. w = 0
  1184. for i in range(len(ac)):
  1185. tw = dc.GetTextExtent(ac[i])[0]
  1186. w = max(w, tw)
  1187. w += offset * 2
  1188. h = show * fi.fy + offset * 2
  1189. itemW = w - offset * 2 + selBleed * 2
  1190. if doSbw:
  1191. w += sbw + offset * 2
  1192. sbh = h - offset * 2 + selBleed * 2
  1193. posY = cursorY + fi.fy + 5
  1194. # if the box doesn't fit on the screen in the normal position, put
  1195. # it above the current line. if it doesn't fit there either,
  1196. # that's just too bad, we don't support window sizes that small.
  1197. if (posY + h) > size.height:
  1198. posY = cursorY - h - 1
  1199. dc.SetPen(cfgGui.autoCompPen)
  1200. dc.SetBrush(cfgGui.autoCompBrush)
  1201. dc.DrawRectangle(posX, posY, w, h)
  1202. dc.SetTextForeground(cfgGui.autoCompFgColor)
  1203. for i in range(startPos, endPos):
  1204. if i == asel:
  1205. dc.SetPen(cfgGui.autoCompRevPen)
  1206. dc.SetBrush(cfgGui.autoCompRevBrush)
  1207. dc.SetTextForeground(cfgGui.autoCompBgColor)
  1208. dc.DrawRectangle(posX + offset - selBleed,
  1209. posY + offset + (i - startPos) * fi.fy - selBleed,
  1210. itemW,
  1211. fi.fy + selBleed * 2)
  1212. dc.SetTextForeground(cfgGui.autoCompBgColor)
  1213. dc.SetPen(cfgGui.autoCompPen)
  1214. dc.SetBrush(cfgGui.autoCompBrush)
  1215. dc.DrawText(ac[i], posX + offset, posY + offset +
  1216. (i - startPos) * fi.fy)
  1217. if i == asel:
  1218. dc.SetTextForeground(cfgGui.autoCompFgColor)
  1219. if doSbw:
  1220. dc.SetPen(cfgGui.autoCompPen)
  1221. dc.SetBrush(cfgGui.autoCompRevBrush)
  1222. util.drawLine(dc, posX + w - offset * 2 - sbw,
  1223. posY, 0, h)
  1224. dc.DrawRectangle(posX + w - offset - sbw,
  1225. posY + offset - selBleed + int((float(startPos) /
  1226. len(ac)) * sbh),
  1227. sbw, int((float(show) / len(ac)) * sbh))
  1228. class MyFrame(wx.Frame):
  1229. def __init__(self, parent, id, title):
  1230. wx.Frame.__init__(self, parent, id, title, name = "Trelby")
  1231. if misc.isUnix:
  1232. # automatically reaps zombies
  1233. signal.signal(signal.SIGCHLD, signal.SIG_IGN)
  1234. self.clipboard = None
  1235. self.showFormatting = False
  1236. self.SetSizeHints(gd.cvars.getMin("width"),
  1237. gd.cvars.getMin("height"))
  1238. self.MoveXY(gd.posX, gd.posY)
  1239. self.SetSize(wx.Size(gd.width, gd.height))
  1240. util.removeTempFiles(misc.tmpPrefix)
  1241. self.mySetIcons()
  1242. self.allocIds()
  1243. fileMenu = wx.Menu()
  1244. fileMenu.Append(ID_FILE_NEW, "&New\tCTRL-N")
  1245. fileMenu.Append(ID_FILE_OPEN, "&Open...\tCTRL-O")
  1246. fileMenu.Append(ID_FILE_SAVE, "&Save\tCTRL-S")
  1247. fileMenu.Append(ID_FILE_SAVE_AS, "Save &As...")
  1248. fileMenu.Append(ID_FILE_CLOSE, "&Close\tCTRL-W")
  1249. fileMenu.Append(ID_FILE_REVERT, "&Revert")
  1250. fileMenu.AppendSeparator()
  1251. fileMenu.Append(ID_FILE_IMPORT, "&Import...")
  1252. fileMenu.Append(ID_FILE_EXPORT, "&Export...")
  1253. fileMenu.AppendSeparator()
  1254. fileMenu.Append(ID_FILE_PRINT, "&Print (via PDF)\tCTRL-P")
  1255. fileMenu.AppendSeparator()
  1256. tmp = wx.Menu()
  1257. tmp.Append(ID_SETTINGS_CHANGE, "&Change...")
  1258. tmp.AppendSeparator()
  1259. tmp.Append(ID_SETTINGS_LOAD, "Load...")
  1260. tmp.Append(ID_SETTINGS_SAVE_AS, "Save as...")
  1261. tmp.AppendSeparator()
  1262. tmp.Append(ID_SETTINGS_SC_DICT, "&Spell checker dictionary...")
  1263. settingsMenu = tmp
  1264. fileMenu.AppendMenu(ID_FILE_SETTINGS, "Se&ttings", tmp)
  1265. fileMenu.AppendSeparator()
  1266. # "most recently used" list comes in here
  1267. fileMenu.AppendSeparator()
  1268. fileMenu.Append(ID_FILE_EXIT, "E&xit\tCTRL-Q")
  1269. editMenu = wx.Menu()
  1270. editMenu.Append(ID_EDIT_UNDO, "&Undo\tCTRL-Z")
  1271. editMenu.Append(ID_EDIT_REDO, "&Redo\tCTRL-Y")
  1272. editMenu.AppendSeparator()
  1273. editMenu.Append(ID_EDIT_CUT, "Cu&t\tCTRL-X")
  1274. editMenu.Append(ID_EDIT_COPY, "&Copy\tCTRL-C")
  1275. editMenu.Append(ID_EDIT_PASTE, "&Paste\tCTRL-V")
  1276. editMenu.AppendSeparator()
  1277. tmp = wx.Menu()
  1278. tmp.Append(ID_EDIT_COPY_TO_CB, "&Unformatted")
  1279. tmp.Append(ID_EDIT_COPY_TO_CB_FMT, "&Formatted")
  1280. editMenu.AppendMenu(ID_EDIT_COPY_SYSTEM, "C&opy (system)", tmp)
  1281. editMenu.Append(ID_EDIT_PASTE_FROM_CB, "P&aste (system)")
  1282. editMenu.AppendSeparator()
  1283. editMenu.Append(ID_EDIT_SELECT_SCENE, "&Select scene")
  1284. editMenu.Append(ID_EDIT_SELECT_ALL, "Select a&ll")
  1285. editMenu.Append(ID_EDIT_GOTO_PAGE, "&Goto page...\tCTRL-G")
  1286. editMenu.Append(ID_EDIT_GOTO_SCENE, "Goto sc&ene...\tALT-G")
  1287. editMenu.AppendSeparator()
  1288. editMenu.Append(ID_EDIT_INSERT_NBSP, "Insert non-breaking space")
  1289. editMenu.AppendSeparator()
  1290. editMenu.Append(ID_EDIT_FIND, "&Find && Replace...\tCTRL-F")
  1291. editMenu.AppendSeparator()
  1292. editMenu.Append(ID_EDIT_DELETE_ELEMENTS, "&Delete elements...")
  1293. viewMenu = wx.Menu()
  1294. viewMenu.AppendRadioItem(ID_VIEW_STYLE_DRAFT, "&Draft")
  1295. viewMenu.AppendRadioItem(ID_VIEW_STYLE_LAYOUT, "&Layout")
  1296. viewMenu.AppendRadioItem(ID_VIEW_STYLE_SIDE_BY_SIDE, "&Side by side")
  1297. viewMenu.AppendRadioItem(ID_VIEW_STYLE_OVERVIEW_SMALL,
  1298. "&Overview - Small")
  1299. viewMenu.AppendRadioItem(ID_VIEW_STYLE_OVERVIEW_LARGE,
  1300. "O&verview - Large")
  1301. if gd.viewMode == VIEWMODE_DRAFT:
  1302. viewMenu.Check(ID_VIEW_STYLE_DRAFT, True)
  1303. elif gd.viewMode == VIEWMODE_LAYOUT:
  1304. viewMenu.Check(ID_VIEW_STYLE_LAYOUT, True)
  1305. elif gd.viewMode == VIEWMODE_SIDE_BY_SIDE:
  1306. viewMenu.Check(ID_VIEW_STYLE_SIDE_BY_SIDE, True)
  1307. elif gd.viewMode == VIEWMODE_OVERVIEW_SMALL:
  1308. viewMenu.Check(ID_VIEW_STYLE_OVERVIEW_SMALL, True)
  1309. else:
  1310. viewMenu.Check(ID_VIEW_STYLE_OVERVIEW_LARGE, True)
  1311. viewMenu.AppendSeparator()
  1312. viewMenu.AppendCheckItem(ID_VIEW_SHOW_FORMATTING, "&Show formatting")
  1313. viewMenu.Append(ID_VIEW_FULL_SCREEN, "&Fullscreen\tF11")
  1314. scriptMenu = wx.Menu()
  1315. scriptMenu.Append(ID_SCRIPT_FIND_ERROR, "&Find next error")
  1316. scriptMenu.Append(ID_SCRIPT_PAGINATE, "&Paginate")
  1317. scriptMenu.AppendSeparator()
  1318. scriptMenu.Append(ID_SCRIPT_AUTO_COMPLETION, "&Auto-completion...")
  1319. scriptMenu.Append(ID_SCRIPT_HEADERS, "&Headers...")
  1320. scriptMenu.Append(ID_SCRIPT_LOCATIONS, "&Locations...")
  1321. scriptMenu.Append(ID_SCRIPT_TITLES, "&Title pages...")
  1322. scriptMenu.Append(ID_SCRIPT_SC_DICT, "&Spell checker dictionary...")
  1323. scriptMenu.AppendSeparator()
  1324. tmp = wx.Menu()
  1325. tmp.Append(ID_SCRIPT_SETTINGS_CHANGE, "&Change...")
  1326. tmp.AppendSeparator()
  1327. tmp.Append(ID_SCRIPT_SETTINGS_LOAD, "&Load...")
  1328. tmp.Append(ID_SCRIPT_SETTINGS_SAVE_AS, "&Save as...")
  1329. scriptMenu.AppendMenu(ID_SCRIPT_SETTINGS, "&Settings", tmp)
  1330. scriptSettingsMenu = tmp
  1331. reportsMenu = wx.Menu()
  1332. reportsMenu.Append(ID_REPORTS_SCRIPT_REP, "Sc&ript report")
  1333. reportsMenu.Append(ID_REPORTS_LOCATION_REP, "&Location report...")
  1334. reportsMenu.Append(ID_REPORTS_SCENE_REP, "&Scene report...")
  1335. reportsMenu.Append(ID_REPORTS_CHARACTER_REP, "&Character report...")
  1336. reportsMenu.Append(ID_REPORTS_DIALOGUE_CHART, "&Dialogue chart...")
  1337. toolsMenu = wx.Menu()
  1338. toolsMenu.Append(ID_TOOLS_SPELL_CHECK, "&Spell checker...")
  1339. toolsMenu.Append(ID_TOOLS_NAME_DB, "&Name database...")
  1340. toolsMenu.Append(ID_TOOLS_CHARMAP, "&Character map...")
  1341. toolsMenu.Append(ID_TOOLS_COMPARE_SCRIPTS, "C&ompare scripts...")
  1342. toolsMenu.Append(ID_TOOLS_WATERMARK, "&Generate watermarked PDFs...")
  1343. helpMenu = wx.Menu()
  1344. helpMenu.Append(ID_HELP_COMMANDS, "&Commands...")
  1345. helpMenu.Append(ID_HELP_MANUAL, "&Manual")
  1346. helpMenu.AppendSeparator()
  1347. helpMenu.Append(ID_HELP_ABOUT, "&About...")
  1348. self.menuBar = wx.MenuBar()
  1349. self.menuBar.Append(fileMenu, "&File")
  1350. self.menuBar.Append(editMenu, "&Edit")
  1351. self.menuBar.Append(viewMenu, "&View")
  1352. self.menuBar.Append(scriptMenu, "Scr&ipt")
  1353. self.menuBar.Append(reportsMenu, "&Reports")
  1354. self.menuBar.Append(toolsMenu, "Too&ls")
  1355. self.menuBar.Append(helpMenu, "&Help")
  1356. self.SetMenuBar(self.menuBar)
  1357. self.toolBar = self.CreateToolBar(wx.TB_VERTICAL)
  1358. def addTB(id, iconFilename, toolTip):
  1359. self.toolBar.AddLabelTool(
  1360. id, "", misc.getBitmap("resources/%s" % iconFilename),
  1361. shortHelp=toolTip)
  1362. addTB(ID_FILE_NEW, "new.png", "New script")
  1363. addTB(ID_FILE_OPEN, "open.png", "Open Script..")
  1364. addTB(ID_FILE_SAVE, "save.png", "Save..")
  1365. addTB(ID_FILE_SAVE_AS, "saveas.png", "Save as..")
  1366. addTB(ID_FILE_CLOSE, "close.png", "Close Script")
  1367. addTB(ID_TOOLBAR_SCRIPTSETTINGS, "scrset.png", "Script settings")
  1368. addTB(ID_FILE_PRINT, "pdf.png", "Print (via PDF)")
  1369. self.toolBar.AddSeparator()
  1370. addTB(ID_FILE_IMPORT, "import.png", "Import a text script")
  1371. addTB(ID_FILE_EXPORT, "export.png", "Export script")
  1372. self.toolBar.AddSeparator()
  1373. addTB(ID_EDIT_UNDO, "undo.png", "Undo")
  1374. addTB(ID_EDIT_REDO, "redo.png", "Redo")
  1375. self.toolBar.AddSeparator()
  1376. addTB(ID_EDIT_FIND, "find.png", "Find / Replace")
  1377. addTB(ID_TOOLBAR_VIEWS, "layout.png", "View mode")
  1378. addTB(ID_TOOLBAR_REPORTS, "report.png", "Script reports")
  1379. addTB(ID_TOOLBAR_TOOLS, "tools.png", "Tools")
  1380. addTB(ID_TOOLBAR_SETTINGS, "settings.png", "Global settings")
  1381. self.toolBar.SetBackgroundColour(cfgGui.tabBarBgColor)
  1382. self.toolBar.Realize()
  1383. wx.EVT_MOVE(self, self.OnMove)
  1384. wx.EVT_SIZE(self, self.OnSize)
  1385. vsizer = wx.BoxSizer(wx.VERTICAL)
  1386. self.SetSizer(vsizer)
  1387. hsizer = wx.BoxSizer(wx.HORIZONTAL)
  1388. self.noFSBtn = misc.MyFSButton(self, -1, getCfgGui)
  1389. self.noFSBtn.SetToolTipString("Exit fullscreen")
  1390. self.noFSBtn.Show(False)
  1391. hsizer.Add(self.noFSBtn)
  1392. wx.EVT_BUTTON(self, self.noFSBtn.GetId(), self.ToggleFullscreen)
  1393. self.tabCtrl = misc.MyTabCtrl(self, -1, getCfgGui)
  1394. hsizer.Add(self.tabCtrl, 1, wx.EXPAND)
  1395. self.statusCtrl = misc.MyStatus(self, -1, getCfgGui)
  1396. hsizer.Add(self.statusCtrl)
  1397. vsizer.Add(hsizer, 0, wx.EXPAND)
  1398. tmp = misc.MyTabCtrl2(self, -1, self.tabCtrl)
  1399. vsizer.Add(tmp, 1, wx.EXPAND)
  1400. vsizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
  1401. gd.mru.useMenu(fileMenu, 14)
  1402. wx.EVT_MENU_HIGHLIGHT_ALL(self, self.OnMenuHighlight)
  1403. self.tabCtrl.setPageChangedFunc(self.OnPageChange)
  1404. # see OnRightDown
  1405. self.rightClickMenu = wx.Menu()
  1406. self.rightClickMenuWithCut = wx.Menu()
  1407. for m in (self.rightClickMenu, self.rightClickMenuWithCut):
  1408. tmp = wx.Menu()
  1409. tmp.Append(ID_ELEM_TO_SCENE, "&Scene")
  1410. tmp.Append(ID_ELEM_TO_ACTION, "&Action")
  1411. tmp.Append(ID_ELEM_TO_CHARACTER, "&Character")
  1412. tmp.Append(ID_ELEM_TO_PAREN, "&Parenthetical")
  1413. tmp.Append(ID_ELEM_TO_DIALOGUE, "&Dialogue")
  1414. tmp.Append(ID_ELEM_TO_TRANSITION, "&Transition")
  1415. tmp.Append(ID_ELEM_TO_SHOT, "Sh&ot")
  1416. tmp.Append(ID_ELEM_TO_ACTBREAK, "Act &break")
  1417. tmp.Append(ID_ELEM_TO_NOTE, "&Note")
  1418. m.AppendSubMenu(tmp, "Element type")
  1419. m.AppendSeparator()
  1420. if m is self.rightClickMenuWithCut:
  1421. m.Append(ID_EDIT_CUT, "Cut")
  1422. m.Append(ID_EDIT_COPY, "Copy")
  1423. m.Append(ID_EDIT_PASTE, "Paste")
  1424. wx.EVT_MENU(self, ID_FILE_NEW, self.OnNewScript)
  1425. wx.EVT_MENU(self, ID_FILE_OPEN, self.OnOpen)
  1426. wx.EVT_MENU(self, ID_FILE_SAVE, self.OnSave)
  1427. wx.EVT_MENU(self, ID_FILE_SAVE_AS, self.OnSaveScriptAs)
  1428. wx.EVT_MENU(self, ID_FILE_IMPORT, self.OnImportScript)
  1429. wx.EVT_MENU(self, ID_FILE_EXPORT, self.OnExportScript)
  1430. wx.EVT_MENU(self, ID_FILE_CLOSE, self.OnCloseScript)
  1431. wx.EVT_MENU(self, ID_FILE_REVERT, self.OnRevertScript)
  1432. wx.EVT_MENU(self, ID_FILE_PRINT, self.OnPrint)
  1433. wx.EVT_MENU(self, ID_SETTINGS_CHANGE, self.OnSettings)
  1434. wx.EVT_MENU(self, ID_SETTINGS_LOAD, self.OnLoadSettings)
  1435. wx.EVT_MENU(self, ID_SETTINGS_SAVE_AS, self.OnSaveSettingsAs)
  1436. wx.EVT_MENU(self, ID_SETTINGS_SC_DICT, self.OnSpellCheckerDictionaryDlg)
  1437. wx.EVT_MENU(self, ID_FILE_EXIT, self.OnExit)
  1438. wx.EVT_MENU(self, ID_EDIT_UNDO, self.OnUndo)
  1439. wx.EVT_MENU(self, ID_EDIT_REDO, self.OnRedo)
  1440. wx.EVT_MENU(self, ID_EDIT_CUT, self.OnCut)
  1441. wx.EVT_MENU(self, ID_EDIT_COPY, self.OnCopy)
  1442. wx.EVT_MENU(self, ID_EDIT_PASTE, self.OnPaste)
  1443. wx.EVT_MENU(self, ID_EDIT_COPY_TO_CB, self.OnCopySystemCb)
  1444. wx.EVT_MENU(self, ID_EDIT_COPY_TO_CB_FMT, self.OnCopySystemCbFormatted)
  1445. wx.EVT_MENU(self, ID_EDIT_PASTE_FROM_CB, self.OnPasteSystemCb)
  1446. wx.EVT_MENU(self, ID_EDIT_SELECT_SCENE, self.OnSelectScene)
  1447. wx.EVT_MENU(self, ID_EDIT_SELECT_ALL, self.OnSelectAll)
  1448. wx.EVT_MENU(self, ID_EDIT_GOTO_PAGE, self.OnGotoPage)
  1449. wx.EVT_MENU(self, ID_EDIT_GOTO_SCENE, self.OnGotoScene)
  1450. wx.EVT_MENU(self, ID_EDIT_INSERT_NBSP, self.OnInsertNbsp)
  1451. wx.EVT_MENU(self, ID_EDIT_FIND, self.OnFind)
  1452. wx.EVT_MENU(self, ID_EDIT_DELETE_ELEMENTS, self.OnDeleteElements)
  1453. wx.EVT_MENU(self, ID_VIEW_STYLE_DRAFT, self.OnViewModeChange)
  1454. wx.EVT_MENU(self, ID_VIEW_STYLE_LAYOUT, self.OnViewModeChange)
  1455. wx.EVT_MENU(self, ID_VIEW_STYLE_SIDE_BY_SIDE, self.OnViewModeChange)
  1456. wx.EVT_MENU(self, ID_VIEW_STYLE_OVERVIEW_SMALL, self.OnViewModeChange)
  1457. wx.EVT_MENU(self, ID_VIEW_STYLE_OVERVIEW_LARGE, self.OnViewModeChange)
  1458. wx.EVT_MENU(self, ID_VIEW_SHOW_FORMATTING, self.OnShowFormatting)
  1459. wx.EVT_MENU(self, ID_VIEW_FULL_SCREEN, self.ToggleFullscreen)
  1460. wx.EVT_MENU(self, ID_SCRIPT_FIND_ERROR, self.OnFindNextError)
  1461. wx.EVT_MENU(self, ID_SCRIPT_PAGINATE, self.OnPaginate)
  1462. wx.EVT_MENU(self, ID_SCRIPT_AUTO_COMPLETION, self.OnAutoCompletionDlg)
  1463. wx.EVT_MENU(self, ID_SCRIPT_HEADERS, self.OnHeadersDlg)
  1464. wx.EVT_MENU(self, ID_SCRIPT_LOCATIONS, self.OnLocationsDlg)
  1465. wx.EVT_MENU(self, ID_SCRIPT_TITLES, self.OnTitlesDlg)
  1466. wx.EVT_MENU(self, ID_SCRIPT_SC_DICT,
  1467. self.OnSpellCheckerScriptDictionaryDlg)
  1468. wx.EVT_MENU(self, ID_SCRIPT_SETTINGS_CHANGE, self.OnScriptSettings)
  1469. wx.EVT_MENU(self, ID_SCRIPT_SETTINGS_LOAD, self.OnLoadScriptSettings)
  1470. wx.EVT_MENU(self, ID_SCRIPT_SETTINGS_SAVE_AS, self.OnSaveScriptSettingsAs)
  1471. wx.EVT_MENU(self, ID_REPORTS_DIALOGUE_CHART, self.OnReportDialogueChart)
  1472. wx.EVT_MENU(self, ID_REPORTS_CHARACTER_REP, self.OnReportCharacter)
  1473. wx.EVT_MENU(self, ID_REPORTS_SCRIPT_REP, self.OnReportScript)
  1474. wx.EVT_MENU(self, ID_REPORTS_LOCATION_REP, self.OnReportLocation)
  1475. wx.EVT_MENU(self, ID_REPORTS_SCENE_REP, self.OnReportScene)
  1476. wx.EVT_MENU(self, ID_TOOLS_SPELL_CHECK, self.OnSpellCheckerDlg)
  1477. wx.EVT_MENU(self, ID_TOOLS_NAME_DB, self.OnNameDatabase)
  1478. wx.EVT_MENU(self, ID_TOOLS_CHARMAP, self.OnCharacterMap)
  1479. wx.EVT_MENU(self, ID_TOOLS_COMPARE_SCRIPTS, self.OnCompareScripts)
  1480. wx.EVT_MENU(self, ID_TOOLS_WATERMARK, self.OnWatermark)
  1481. wx.EVT_MENU(self, ID_HELP_COMMANDS, self.OnHelpCommands)
  1482. wx.EVT_MENU(self, ID_HELP_MANUAL, self.OnHelpManual)
  1483. wx.EVT_MENU(self, ID_HELP_ABOUT, self.OnAbout)
  1484. wx.EVT_MENU_RANGE(self, gd.mru.getIds()[0], gd.mru.getIds()[1],
  1485. self.OnMRUFile)
  1486. wx.EVT_MENU_RANGE(self, ID_ELEM_TO_ACTION, ID_ELEM_TO_TRANSITION,
  1487. self.OnChangeType)
  1488. def addTBMenu(id, menu):
  1489. wx.EVT_MENU(self, id, partial(self.OnToolBarMenu, menu=menu))
  1490. addTBMenu(ID_TOOLBAR_SETTINGS, settingsMenu)
  1491. addTBMenu(ID_TOOLBAR_SCRIPTSETTINGS, scriptSettingsMenu)
  1492. addTBMenu(ID_TOOLBAR_REPORTS, reportsMenu)
  1493. addTBMenu(ID_TOOLBAR_VIEWS, viewMenu)
  1494. addTBMenu(ID_TOOLBAR_TOOLS, toolsMenu)
  1495. wx.EVT_CLOSE(self, self.OnCloseWindow)
  1496. wx.EVT_SET_FOCUS(self, self.OnFocus)
  1497. self.Layout()
  1498. def init(self):
  1499. self.updateKbdCommands()
  1500. self.panel = self.createNewPanel()
  1501. def mySetIcons(self):
  1502. wx.Image_AddHandler(wx.PNGHandler())
  1503. ib = wx.IconBundle()
  1504. for sz in ("16", "32", "64", "128", "256"):
  1505. ib.AddIcon(wx.IconFromBitmap(misc.getBitmap("resources/icon%s.png" % sz)))
  1506. self.SetIcons(ib)
  1507. def allocIds(self):
  1508. names = [
  1509. "ID_EDIT_UNDO",
  1510. "ID_EDIT_REDO",
  1511. "ID_EDIT_COPY",
  1512. "ID_EDIT_COPY_SYSTEM",
  1513. "ID_EDIT_COPY_TO_CB",
  1514. "ID_EDIT_COPY_TO_CB_FMT",
  1515. "ID_EDIT_CUT",
  1516. "ID_EDIT_DELETE_ELEMENTS",
  1517. "ID_EDIT_FIND",
  1518. "ID_EDIT_GOTO_SCENE",
  1519. "ID_EDIT_GOTO_PAGE",
  1520. "ID_EDIT_INSERT_NBSP",
  1521. "ID_EDIT_PASTE",
  1522. "ID_EDIT_PASTE_FROM_CB",
  1523. "ID_EDIT_SELECT_ALL",
  1524. "ID_EDIT_SELECT_SCENE",
  1525. "ID_FILE_CLOSE",
  1526. "ID_FILE_EXIT",
  1527. "ID_FILE_EXPORT",
  1528. "ID_FILE_IMPORT",
  1529. "ID_FILE_NEW",
  1530. "ID_FILE_OPEN",
  1531. "ID_FILE_PRINT",
  1532. "ID_FILE_REVERT",
  1533. "ID_FILE_SAVE",
  1534. "ID_FILE_SAVE_AS",
  1535. "ID_FILE_SETTINGS",
  1536. "ID_HELP_ABOUT",
  1537. "ID_HELP_COMMANDS",
  1538. "ID_HELP_MANUAL",
  1539. "ID_REPORTS_CHARACTER_REP",
  1540. "ID_REPORTS_DIALOGUE_CHART",
  1541. "ID_REPORTS_LOCATION_REP",
  1542. "ID_REPORTS_SCENE_REP",
  1543. "ID_REPORTS_SCRIPT_REP",
  1544. "ID_SCRIPT_AUTO_COMPLETION",
  1545. "ID_SCRIPT_FIND_ERROR",
  1546. "ID_SCRIPT_HEADERS",
  1547. "ID_SCRIPT_LOCATIONS",
  1548. "ID_SCRIPT_PAGINATE",
  1549. "ID_SCRIPT_SC_DICT",
  1550. "ID_SCRIPT_SETTINGS",
  1551. "ID_SCRIPT_SETTINGS_CHANGE",
  1552. "ID_SCRIPT_SETTINGS_LOAD",
  1553. "ID_SCRIPT_SETTINGS_SAVE_AS",
  1554. "ID_SCRIPT_TITLES",
  1555. "ID_SETTINGS_CHANGE",
  1556. "ID_SETTINGS_LOAD",
  1557. "ID_SETTINGS_SAVE_AS",
  1558. "ID_SETTINGS_SC_DICT",
  1559. "ID_TOOLS_CHARMAP",
  1560. "ID_TOOLS_COMPARE_SCRIPTS",
  1561. "ID_TOOLS_NAME_DB",
  1562. "ID_TOOLS_SPELL_CHECK",
  1563. "ID_TOOLS_WATERMARK",
  1564. "ID_VIEW_SHOW_FORMATTING",
  1565. "ID_VIEW_STYLE_DRAFT",
  1566. "ID_VIEW_STYLE_LAYOUT",
  1567. "ID_VIEW_STYLE_OVERVIEW_LARGE",
  1568. "ID_VIEW_STYLE_OVERVIEW_SMALL",
  1569. "ID_VIEW_STYLE_SIDE_BY_SIDE",
  1570. "ID_TOOLBAR_SETTINGS",
  1571. "ID_TOOLBAR_SCRIPTSETTINGS",
  1572. "ID_TOOLBAR_REPORTS",
  1573. "ID_TOOLBAR_VIEWS",
  1574. "ID_TOOLBAR_TOOLS",
  1575. "ID_VIEW_FULL_SCREEN",
  1576. "ID_ELEM_TO_ACTION",
  1577. "ID_ELEM_TO_CHARACTER",
  1578. "ID_ELEM_TO_DIALOGUE",
  1579. "ID_ELEM_TO_NOTE",
  1580. "ID_ELEM_TO_PAREN",
  1581. "ID_ELEM_TO_SCENE",
  1582. "ID_ELEM_TO_SHOT",
  1583. "ID_ELEM_TO_ACTBREAK",
  1584. "ID_ELEM_TO_TRANSITION",
  1585. ]
  1586. g = globals()
  1587. for n in names:
  1588. g[n] = wx.NewId()
  1589. # see OnChangeType
  1590. g["idToLTMap"] = {
  1591. ID_ELEM_TO_SCENE : screenplay.SCENE,
  1592. ID_ELEM_TO_ACTION : screenplay.ACTION,
  1593. ID_ELEM_TO_CHARACTER : screenplay.CHARACTER,
  1594. ID_ELEM_TO_DIALOGUE : screenplay.DIALOGUE,
  1595. ID_ELEM_TO_PAREN : screenplay.PAREN,
  1596. ID_ELEM_TO_TRANSITION : screenplay.TRANSITION,
  1597. ID_ELEM_TO_SHOT : screenplay.SHOT,
  1598. ID_ELEM_TO_ACTBREAK : screenplay.ACTBREAK,
  1599. ID_ELEM_TO_NOTE : screenplay.NOTE,
  1600. }
  1601. def createNewPanel(self):
  1602. newPanel = MyPanel(self.tabCtrl.getTabParent(), -1)
  1603. self.tabCtrl.addPage(newPanel, u"")
  1604. newPanel.ctrl.setTabText()
  1605. newPanel.ctrl.SetFocus()
  1606. return newPanel
  1607. def setTitle(self, text):
  1608. self.SetTitle("Trelby - %s" % text)
  1609. def setTabText(self, panel, text):
  1610. i = self.findPage(panel)
  1611. if i != -1:
  1612. # strip out ".trelby" suffix from tab names (it's a bit
  1613. # complicated since if we open the same file multiple times,
  1614. # we have e.g. "foo.trelby" and "foo.trelby<2>", so actually
  1615. # we just strip out ".trelby" if it's found anywhere in the
  1616. # string)
  1617. s = text.replace(".trelby", "")
  1618. self.tabCtrl.setTabText(i, s)
  1619. # iterates over all tabs and finds out the corresponding page number
  1620. # for the given panel.
  1621. def findPage(self, panel):
  1622. for i in range(self.tabCtrl.getPageCount()):
  1623. p = self.tabCtrl.getPage(i)
  1624. if p == panel:
  1625. return i
  1626. return -1
  1627. # get list of MyCtrl objects for all open scripts
  1628. def getCtrls(self):
  1629. l = []
  1630. for i in range(self.tabCtrl.getPageCount()):
  1631. l.append(self.tabCtrl.getPage(i).ctrl)
  1632. return l
  1633. # returns True if any open script has been modified
  1634. def isModifications(self):
  1635. for c in self.getCtrls():
  1636. if c.sp.isModified():
  1637. return True
  1638. return False
  1639. def updateKbdCommands(self):
  1640. cfgGl.addShiftKeys()
  1641. if cfgGl.getConflictingKeys() != None:
  1642. wx.MessageBox("You have at least one key bound to more than one\n"
  1643. "command. The program will not work correctly until\n"
  1644. "you fix this.",
  1645. "Warning", wx.OK, self)
  1646. self.kbdCommands = {}
  1647. for cmd in cfgGl.commands:
  1648. if not (cmd.isFixed and cmd.isMenu):
  1649. for key in cmd.keys:
  1650. self.kbdCommands[key] = cmd
  1651. # open script, in the current tab if it's untouched, or in a new one
  1652. # otherwise
  1653. def openScript(self, filename):
  1654. if not self.tabCtrl.getPage(self.findPage(self.panel))\
  1655. .ctrl.isUntouched():
  1656. self.panel = self.createNewPanel()
  1657. self.panel.ctrl.loadFile(filename)
  1658. self.panel.ctrl.updateScreen()
  1659. gd.mru.add(filename)
  1660. def checkFonts(self):
  1661. names = ["Normal", "Bold", "Italic", "Bold-Italic"]
  1662. failed = []
  1663. for i, fi in enumerate(cfgGui.fonts):
  1664. if not util.isFixedWidth(fi.font):
  1665. failed.append(names[i])
  1666. if failed:
  1667. wx.MessageBox(
  1668. "The fonts listed below are not fixed width and\n"
  1669. "will cause the program not to function correctly.\n"
  1670. "Please change the fonts at File/Settings/Change.\n\n"
  1671. + "\n".join(failed), "Error", wx.OK, self)
  1672. # If we get focus, pass it on to ctrl.
  1673. def OnFocus(self, event):
  1674. self.panel.ctrl.SetFocus()
  1675. def OnMenuHighlight(self, event):
  1676. # default implementation modifies status bar, so we need to
  1677. # override it and do nothing
  1678. pass
  1679. def OnPageChange(self, page):
  1680. self.panel = self.tabCtrl.getPage(page)
  1681. self.panel.ctrl.SetFocus()
  1682. self.panel.ctrl.updateCommon()
  1683. self.setTitle(self.panel.ctrl.fileNameDisplay)
  1684. def selectScript(self, toNext):
  1685. current = self.tabCtrl.getSelectedPageIndex()
  1686. pageCnt = self.tabCtrl.getPageCount()
  1687. if toNext:
  1688. pageNr = current + 1
  1689. else:
  1690. pageNr = current - 1
  1691. if pageNr == -1:
  1692. pageNr = pageCnt - 1
  1693. elif pageNr == pageCnt:
  1694. pageNr = 0
  1695. if pageNr == current:
  1696. # only one tab, nothing to do
  1697. return
  1698. self.tabCtrl.selectPage(pageNr)
  1699. def OnScriptNext(self, event = None):
  1700. self.selectScript(True)
  1701. def OnScriptPrev(self, event = None):
  1702. self.selectScript(False)
  1703. def OnNewScript(self, event = None):
  1704. self.panel = self.createNewPanel()
  1705. def OnMRUFile(self, event):
  1706. i = event.GetId() - gd.mru.getIds()[0]
  1707. self.openScript(gd.mru.get(i))
  1708. def OnOpen(self, event = None):
  1709. dlg = wx.FileDialog(self, "File to open",
  1710. misc.scriptDir,
  1711. wildcard = "Trelby files (*.trelby)|*.trelby|All files|*",
  1712. style = wx.OPEN)
  1713. if dlg.ShowModal() == wx.ID_OK:
  1714. misc.scriptDir = dlg.GetDirectory()
  1715. self.openScript(dlg.GetPath())
  1716. dlg.Destroy()
  1717. def OnSave(self, event = None):
  1718. self.panel.ctrl.OnSave()
  1719. def OnSaveScriptAs(self, event = None):
  1720. self.panel.ctrl.OnSaveScriptAs()
  1721. def OnImportScript(self, event = None):
  1722. dlg = wx.FileDialog(self, "File to import",
  1723. misc.scriptDir,
  1724. wildcard = "Importable files (*.txt;*.fdx;*.celtx;*.astx;*.fountain;*.fadein)|" +
  1725. "*.fdx;*.txt;*.celtx;*.astx;*.fountain;*.fadein|" +
  1726. "Formatted text files (*.txt)|*.txt|" +
  1727. "Final Draft XML(*.fdx)|*.fdx|" +
  1728. "Celtx files (*.celtx)|*.celtx|" +
  1729. "Adobe Story XML files (*.astx)|*.astx|" +
  1730. "Fountain files (*.fountain)|*.fountain|" +
  1731. "Fadein files (*.fadein)|*.fadein|" +
  1732. "All files|*",
  1733. style = wx.OPEN)
  1734. if dlg.ShowModal() == wx.ID_OK:
  1735. misc.scriptDir = dlg.GetDirectory()
  1736. if not self.tabCtrl.getPage(self.findPage(self.panel))\
  1737. .ctrl.isUntouched():
  1738. self.panel = self.createNewPanel()
  1739. self.panel.ctrl.importFile(dlg.GetPath())
  1740. self.panel.ctrl.updateScreen()
  1741. dlg.Destroy()
  1742. def OnExportScript(self, event = None):
  1743. self.panel.ctrl.OnExportScript()
  1744. def OnCloseScript(self, event = None):
  1745. if not self.panel.ctrl.canBeClosed():
  1746. return
  1747. if self.tabCtrl.getPageCount() > 1:
  1748. self.tabCtrl.deletePage(self.tabCtrl.getSelectedPageIndex())
  1749. else:
  1750. self.panel.ctrl.createEmptySp()
  1751. self.panel.ctrl.updateScreen()
  1752. def OnRevertScript(self, event = None):
  1753. self.panel.ctrl.OnRevertScript()
  1754. def OnPrint(self, event = None):
  1755. self.panel.ctrl.OnPrint()
  1756. def OnSettings(self, event = None):
  1757. self.panel.ctrl.OnSettings()
  1758. def OnLoadSettings(self, event = None):
  1759. dlg = wx.FileDialog(self, "File to open",
  1760. defaultDir = os.path.dirname(gd.confFilename),
  1761. defaultFile = os.path.basename(gd.confFilename),
  1762. wildcard = "Setting files (*.conf)|*.conf|All files|*",
  1763. style = wx.OPEN)
  1764. if dlg.ShowModal() == wx.ID_OK:
  1765. s = util.loadFile(dlg.GetPath(), self)
  1766. if s:
  1767. c = config.ConfigGlobal()
  1768. c.load(s)
  1769. gd.confFilename = dlg.GetPath()
  1770. self.panel.ctrl.applyGlobalCfg(c, False)
  1771. dlg.Destroy()
  1772. def OnSaveSettingsAs(self, event = None):
  1773. dlg = wx.FileDialog(self, "Filename to save as",
  1774. defaultDir = os.path.dirname(gd.confFilename),
  1775. defaultFile = os.path.basename(gd.confFilename),
  1776. wildcard = "Setting files (*.conf)|*.conf|All files|*",
  1777. style = wx.SAVE | wx.OVERWRITE_PROMPT)
  1778. if dlg.ShowModal() == wx.ID_OK:
  1779. if util.writeToFile(dlg.GetPath(), cfgGl.save(), self):
  1780. gd.confFilename = dlg.GetPath()
  1781. dlg.Destroy()
  1782. def OnUndo(self, event = None):
  1783. self.panel.ctrl.OnUndo()
  1784. def OnRedo(self, event = None):
  1785. self.panel.ctrl.OnRedo()
  1786. def OnCut(self, event = None):
  1787. self.panel.ctrl.OnCut()
  1788. def OnCopy(self, event = None):
  1789. self.panel.ctrl.OnCopy()
  1790. def OnCopySystemCb(self, event = None):
  1791. self.panel.ctrl.OnCopySystem(formatted = False)
  1792. def OnCopySystemCbFormatted(self, event = None):
  1793. self.panel.ctrl.OnCopySystem(formatted = True)
  1794. def OnPaste(self, event = None):
  1795. self.panel.ctrl.OnPaste()
  1796. def OnPasteSystemCb(self, event = None):
  1797. self.panel.ctrl.OnPasteSystemCb()
  1798. def OnSelectScene(self, event = None):
  1799. self.panel.ctrl.OnSelectScene()
  1800. def OnSelectAll(self, event = None):
  1801. self.panel.ctrl.OnSelectAll()
  1802. def OnGotoPage(self, event = None):
  1803. self.panel.ctrl.OnGotoPage()
  1804. def OnGotoScene(self, event = None):
  1805. self.panel.ctrl.OnGotoScene()
  1806. def OnFindNextError(self, event = None):
  1807. self.panel.ctrl.OnFindNextError()
  1808. def OnFind(self, event = None):
  1809. self.panel.ctrl.OnFind()
  1810. def OnInsertNbsp(self, event = None):
  1811. self.panel.ctrl.OnInsertNbsp()
  1812. def OnDeleteElements(self, event = None):
  1813. self.panel.ctrl.OnDeleteElements()
  1814. def OnToggleShowFormatting(self, event = None):
  1815. self.menuBar.Check(ID_VIEW_SHOW_FORMATTING,
  1816. not self.menuBar.IsChecked(ID_VIEW_SHOW_FORMATTING))
  1817. self.showFormatting = not self.showFormatting
  1818. self.panel.ctrl.Refresh(False)
  1819. def OnShowFormatting(self, event = None):
  1820. self.showFormatting = self.menuBar.IsChecked(ID_VIEW_SHOW_FORMATTING)
  1821. self.panel.ctrl.Refresh(False)
  1822. def OnViewModeDraft(self):
  1823. self.menuBar.Check(ID_VIEW_STYLE_DRAFT, True)
  1824. self.OnViewModeChange()
  1825. def OnViewModeLayout(self):
  1826. self.menuBar.Check(ID_VIEW_STYLE_LAYOUT, True)
  1827. self.OnViewModeChange()
  1828. def OnViewModeSideBySide(self):
  1829. self.menuBar.Check(ID_VIEW_STYLE_SIDE_BY_SIDE, True)
  1830. self.OnViewModeChange()
  1831. def OnViewModeOverviewSmall(self):
  1832. self.menuBar.Check(ID_VIEW_STYLE_OVERVIEW_SMALL, True)
  1833. self.OnViewModeChange()
  1834. def OnViewModeOverviewLarge(self):
  1835. self.menuBar.Check(ID_VIEW_STYLE_OVERVIEW_LARGE, True)
  1836. self.OnViewModeChange()
  1837. def OnViewModeChange(self, event = None):
  1838. if self.menuBar.IsChecked(ID_VIEW_STYLE_DRAFT):
  1839. mode = VIEWMODE_DRAFT
  1840. elif self.menuBar.IsChecked(ID_VIEW_STYLE_LAYOUT):
  1841. mode = VIEWMODE_LAYOUT
  1842. elif self.menuBar.IsChecked(ID_VIEW_STYLE_SIDE_BY_SIDE):
  1843. mode = VIEWMODE_SIDE_BY_SIDE
  1844. elif self.menuBar.IsChecked(ID_VIEW_STYLE_OVERVIEW_SMALL):
  1845. mode = VIEWMODE_OVERVIEW_SMALL
  1846. else:
  1847. mode = VIEWMODE_OVERVIEW_LARGE
  1848. gd.setViewMode(mode)
  1849. for c in self.getCtrls():
  1850. c.refreshCache()
  1851. c = self.panel.ctrl
  1852. c.makeLineVisible(c.sp.line)
  1853. c.updateScreen()
  1854. def ToggleFullscreen(self, event = None):
  1855. self.noFSBtn.Show(not self.IsFullScreen())
  1856. self.ShowFullScreen(not self.IsFullScreen(), wx.FULLSCREEN_ALL)
  1857. self.panel.ctrl.SetFocus()
  1858. def OnPaginate(self, event = None):
  1859. self.panel.ctrl.OnPaginate()
  1860. def OnAutoCompletionDlg(self, event = None):
  1861. self.panel.ctrl.OnAutoCompletionDlg()
  1862. def OnTitlesDlg(self, event = None):
  1863. self.panel.ctrl.OnTitlesDlg()
  1864. def OnHeadersDlg(self, event = None):
  1865. self.panel.ctrl.OnHeadersDlg()
  1866. def OnLocationsDlg(self, event = None):
  1867. self.panel.ctrl.OnLocationsDlg()
  1868. def OnSpellCheckerDictionaryDlg(self, event = None):
  1869. dlg = spellcheckcfgdlg.SCDictDlg(self, copy.deepcopy(gd.scDict),
  1870. True)
  1871. if dlg.ShowModal() == wx.ID_OK:
  1872. gd.scDict = dlg.scDict
  1873. gd.saveScDict()
  1874. dlg.Destroy()
  1875. def OnSpellCheckerScriptDictionaryDlg(self, event = None):
  1876. self.panel.ctrl.OnSpellCheckerScriptDictionaryDlg()
  1877. def OnWatermark(self, event = None):
  1878. self.panel.ctrl.OnWatermark()
  1879. def OnScriptSettings(self, event = None):
  1880. self.panel.ctrl.OnScriptSettings()
  1881. def OnLoadScriptSettings(self, event = None):
  1882. dlg = wx.FileDialog(self, "File to open",
  1883. defaultDir = gd.scriptSettingsPath,
  1884. wildcard = "Script setting files (*.sconf)|*.sconf|All files|*",
  1885. style = wx.OPEN)
  1886. if dlg.ShowModal() == wx.ID_OK:
  1887. s = util.loadFile(dlg.GetPath(), self)
  1888. if s:
  1889. cfg = config.Config()
  1890. cfg.load(s)
  1891. self.panel.ctrl.applyCfg(cfg)
  1892. gd.scriptSettingsPath = os.path.dirname(dlg.GetPath())
  1893. dlg.Destroy()
  1894. def OnSaveScriptSettingsAs(self, event = None):
  1895. dlg = wx.FileDialog(self, "Filename to save as",
  1896. defaultDir = gd.scriptSettingsPath,
  1897. wildcard = "Script setting files (*.sconf)|*.sconf|All files|*",
  1898. style = wx.SAVE | wx.OVERWRITE_PROMPT)
  1899. if dlg.ShowModal() == wx.ID_OK:
  1900. if util.writeToFile(dlg.GetPath(), self.panel.ctrl.sp.saveCfg(), self):
  1901. gd.scriptSettingsPath = os.path.dirname(dlg.GetPath())
  1902. dlg.Destroy()
  1903. def OnReportCharacter(self, event = None):
  1904. self.panel.ctrl.OnReportCharacter()
  1905. def OnReportDialogueChart(self, event = None):
  1906. self.panel.ctrl.OnReportDialogueChart()
  1907. def OnReportLocation(self, event = None):
  1908. self.panel.ctrl.OnReportLocation()
  1909. def OnReportScene(self, event = None):
  1910. self.panel.ctrl.OnReportScene()
  1911. def OnReportScript(self, event = None):
  1912. self.panel.ctrl.OnReportScript()
  1913. def OnSpellCheckerDlg(self, event = None):
  1914. self.panel.ctrl.OnSpellCheckerDlg()
  1915. def OnNameDatabase(self, event = None):
  1916. if not namesdlg.readNames(self):
  1917. wx.MessageBox("Error opening name database.", "Error",
  1918. wx.OK, self)
  1919. return
  1920. dlg = namesdlg.NamesDlg(self, self.panel.ctrl)
  1921. dlg.ShowModal()
  1922. dlg.Destroy()
  1923. def OnCharacterMap(self, event = None):
  1924. dlg = charmapdlg.CharMapDlg(self, self.panel.ctrl)
  1925. dlg.ShowModal()
  1926. dlg.Destroy()
  1927. def OnCompareScripts(self, event = None):
  1928. self.panel.ctrl.OnCompareScripts()
  1929. def OnChangeType(self, event):
  1930. self.panel.ctrl.OnChangeType(event)
  1931. def OnHelpCommands(self, event = None):
  1932. dlg = commandsdlg.CommandsDlg(cfgGl)
  1933. dlg.Show()
  1934. def OnHelpManual(self, event = None):
  1935. wx.LaunchDefaultBrowser("file://" + misc.getFullPath("manual.html"))
  1936. def OnAbout(self, event = None):
  1937. win = splash.SplashWindow(self, -1)
  1938. win.Show()
  1939. def OnToolBarMenu(self, event, menu):
  1940. self.PopupMenu(menu)
  1941. def OnCloseWindow(self, event):
  1942. doExit = True
  1943. if event.CanVeto() and self.isModifications():
  1944. if wx.MessageBox("You have unsaved changes. Are\n"
  1945. "you sure you want to exit?", "Confirm",
  1946. wx.YES_NO | wx.NO_DEFAULT, self) == wx.NO:
  1947. doExit = False
  1948. if doExit:
  1949. util.writeToFile(gd.stateFilename, gd.save(), self)
  1950. util.removeTempFiles(misc.tmpPrefix)
  1951. self.Destroy()
  1952. myApp.ExitMainLoop()
  1953. else:
  1954. event.Veto()
  1955. def OnExit(self, event):
  1956. self.Close(False)
  1957. def OnMove(self, event):
  1958. gd.posX, gd.posY = self.GetPositionTuple()
  1959. event.Skip()
  1960. def OnSize(self, event):
  1961. gd.width, gd.height = self.GetSizeTuple()
  1962. event.Skip()
  1963. class MyApp(wx.App):
  1964. def OnInit(self):
  1965. global cfgGl, mainFrame, gd
  1966. if (wx.MAJOR_VERSION != 2) or (wx.MINOR_VERSION != 8):
  1967. wx.MessageBox("You seem to have an invalid version\n"
  1968. "(%s) of wxWidgets installed. This\n"
  1969. "program needs version 2.8." %
  1970. wx.VERSION_STRING, "Error", wx.OK)
  1971. sys.exit()
  1972. misc.init()
  1973. util.init()
  1974. gd = GlobalData()
  1975. if misc.isWindows:
  1976. major = sys.getwindowsversion()[0]
  1977. if major < 5:
  1978. wx.MessageBox("You seem to have a version of Windows\n"
  1979. "older than Windows 2000, which is the minimum\n"
  1980. "requirement for this program.", "Error", wx.OK)
  1981. sys.exit()
  1982. if not misc.wxIsUnicode:
  1983. wx.MessageBox("You seem to be using a non-Unicode build of\n"
  1984. "wxWidgets. This is not supported.",
  1985. "Error", wx.OK)
  1986. sys.exit()
  1987. # by setting this, we don't have to convert from 8-bit strings to
  1988. # Unicode ourselves everywhere when we pass them to wxWidgets.
  1989. wx.SetDefaultPyEncoding("ISO-8859-1")
  1990. os.chdir(misc.progPath)
  1991. cfgGl = config.ConfigGlobal()
  1992. cfgGl.setDefaults()
  1993. if util.fileExists(gd.confFilename):
  1994. s = util.loadFile(gd.confFilename, None)
  1995. if s:
  1996. cfgGl.load(s)
  1997. else:
  1998. # we want to write out a default config file at startup for
  1999. # various reasons, if no default config file yet exists
  2000. util.writeToFile(gd.confFilename, cfgGl.save(), None)
  2001. refreshGuiConfig()
  2002. # cfgGl.scriptDir is the directory used on startup, while
  2003. # misc.scriptDir is updated every time the user opens something in
  2004. # a different directory.
  2005. misc.scriptDir = cfgGl.scriptDir
  2006. if util.fileExists(gd.stateFilename):
  2007. s = util.loadFile(gd.stateFilename, None)
  2008. if s:
  2009. gd.load(s)
  2010. gd.setViewMode(gd.viewMode)
  2011. if util.fileExists(gd.scDictFilename):
  2012. s = util.loadFile(gd.scDictFilename, None)
  2013. if s:
  2014. gd.scDict.load(s)
  2015. mainFrame = MyFrame(None, -1, "Trelby")
  2016. mainFrame.init()
  2017. for arg in opts.filenames:
  2018. mainFrame.openScript(arg)
  2019. mainFrame.Show(True)
  2020. # windows needs this for some reason
  2021. mainFrame.panel.ctrl.SetFocus()
  2022. self.SetTopWindow(mainFrame)
  2023. mainFrame.checkFonts()
  2024. if cfgGl.splashTime > 0:
  2025. win = splash.SplashWindow(mainFrame, cfgGl.splashTime * 1000)
  2026. win.Show()
  2027. win.Raise()
  2028. return True
  2029. def main():
  2030. global myApp
  2031. opts.init()
  2032. myApp = MyApp(0)
  2033. myApp.MainLoop()