design.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import os, re
  4. # sys,
  5. from PyQt5 import QtCore
  6. from PyQt5.QtCore import QUrl, QSettings, QSizeF
  7. from PyQt5.QtGui import QKeySequence, QFont
  8. from PyQt5.QtWidgets import QWidget, QTabWidget, QVBoxLayout, QHBoxLayout, QSplitter, QPlainTextEdit, QShortcut, QPushButton, QCheckBox, QSpinBox, QLabel
  9. from PyQt5.QtWebKit import QWebSettings
  10. from PyQt5.QtWebKitWidgets import QWebView, QWebInspector
  11. from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter
  12. # from pygments import highlight
  13. # from pygments.lexers import *
  14. # from pygments.formatter import Formatter
  15. from classes import highlighter
  16. class WebkitView(QWebView):
  17. def __init__(self, parent, core):
  18. self.parent = parent
  19. self.core = core
  20. self.port = core.server.port
  21. self.view = QWebView.__init__(self, parent)
  22. self.setZoomFactor(1)
  23. self.load(QUrl('http://localhost:'+str(self.port)))
  24. self.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
  25. # self.settings().setAttribute(QWebSettings.PluginsEnabled, True)
  26. self.initPDF()
  27. # self.mainframe = self.page.mainFrame()
  28. # print(self.mainframe)
  29. def initPDF(self):
  30. self.printer = QPrinter(QPrinter.HighResolution)
  31. self.printer.setFullPage(True)
  32. # self.printer.setPageMargins(0,0,0,0,QPrinter.Millimeter)
  33. self.printer.setFontEmbeddingEnabled(True)
  34. self.printer.setColorMode(QPrinter.Color)
  35. # TODO: set the page size and orientation from doc settings
  36. # (need to do doc settings before that)
  37. # self.printer.setPageSize(QPrinter.A4)
  38. self.printer.setPaperSize(QSizeF(210, 300), QPrinter.Millimeter)
  39. # self.printer.setOrientation(QPrinter.Portrait)
  40. self.printer.setOutputFormat(QPrinter.PdfFormat)
  41. self.printer.setCreator('Cascade')
  42. self.printer.setDocName(self.core.projectname)
  43. self.printer.setOutputFileName(self.core.projectname+".pdf")
  44. # self.setFixedWidth(1000)
  45. def ongenPDF(self):
  46. # QPrinter::Custom
  47. # dialog = QPrintPreviewDialog(self.printer)
  48. # dialog.setWindowState(Qt.WindowMaximized)
  49. # dialog.paintRequested.connect(self.print_)
  50. # dialog.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint | Qt.WindowContextHelpButtonHint)
  51. # dialog.exec()
  52. # TODO: open a dialogue to ask where to save the pdf
  53. # TODO: reload webview and wait for it before printing
  54. # TODO: addd a progress bar
  55. # self.webview.
  56. self.print_(self.printer)
  57. def refresh(self):
  58. self.initPDF()
  59. self.reload()
  60. def toggleDocClass(self, c="",a=True):
  61. if a :
  62. togg = "add"
  63. else :
  64. togg = "remove"
  65. command = """document.documentElement.classList."""+togg+"""('"""+c+"""')"""
  66. self.evaluateJS(command)
  67. def evaluateJS(self, command):
  68. self.page().mainFrame().evaluateJavaScript(command)
  69. class WebkitInspector(QWebInspector):
  70. def __init__(self, parent, webkitview):
  71. super(WebkitInspector, self).__init__(parent)
  72. self.webkitview = webkitview
  73. self.setPage(self.webkitview.page())
  74. self.showMaximized()
  75. # TODO: webkitinspector is disappearing when chaging tabs
  76. class WebViewToolBar(QWidget):
  77. def __init__(self, parent):
  78. super(WebViewToolBar, self).__init__(parent)
  79. self.parent = parent
  80. font = QFont()
  81. # font.setFamily("Droid Sans Mono")
  82. # font.setFixedPitch(True)
  83. font.setPointSize(8)
  84. self.setFont(font)
  85. self.hbox = QHBoxLayout()
  86. self.hbox.setContentsMargins(0,0,0,0)
  87. self.preview = QCheckBox('Prev&iew', self)
  88. # self.preview.setShortcut('Ctrl+Shift+p')
  89. self.preview.clicked.connect(self.onPreview)
  90. self.hbox.addWidget(self.preview)
  91. self.debug = QCheckBox('Deb&ug', self)
  92. # self.debug.setShortcut('Ctrl+Shift+u')
  93. self.debug.clicked.connect(self.onDebug)
  94. self.hbox.addWidget(self.debug)
  95. self.grid = QCheckBox('&Grid', self)
  96. # self.grid.setShortcut('Ctrl+Shift+g')
  97. self.grid.clicked.connect(self.onGrid)
  98. self.hbox.addWidget(self.grid)
  99. # spread
  100. self.spread = QCheckBox('&Spread', self)
  101. # self.spread.setShortcut('Ctrl+Shift+g')
  102. self.spread.clicked.connect(self.onSpread)
  103. self.hbox.addWidget(self.spread)
  104. self.hbox.addStretch()
  105. # zoom
  106. self.hbox.addWidget(QLabel("Zoom:"))
  107. self.zoom = QSpinBox(self)
  108. # TODO: action
  109. self.hbox.addWidget(self.zoom)
  110. # page
  111. self.hbox.addWidget(QLabel("Page:"))
  112. self.page = QSpinBox(self)
  113. # TODO: action
  114. self.hbox.addWidget(self.page)
  115. self.addpage = QPushButton("&Add Page", self)
  116. # self.addpage.setShortcut('Ctrl+Shift+r')
  117. # TODO: how to define same shortcut in different places
  118. # self.addpage.setIcon(Icon(ico)))
  119. # self.addpage.clicked.connect(self.onAddPage)
  120. self.hbox.addWidget(self.addpage)
  121. self.hbox.addStretch()
  122. self.reload = QPushButton("&Reload", self)
  123. # self.reload.setShortcut('Ctrl+Shift+r')
  124. # TODO: how to define same shortcut in different places
  125. # self.reload.setIcon(Icon(ico)))
  126. self.reload.clicked.connect(self.onReload)
  127. self.hbox.addWidget(self.reload)
  128. self.genpdf = QPushButton("&PDF", self)
  129. # self.genpdf.setShortcut('Ctrl+Shift+r')
  130. # TODO: how to define same shortcut in different places
  131. # self.genpdf.setIcon(Icon(ico)))
  132. self.genpdf.clicked.connect(self.onGenPDF)
  133. self.hbox.addWidget(self.genpdf)
  134. self.setLayout(self.hbox)
  135. def onPreview(self):
  136. self.parent.webkitview.toggleDocClass('preview', self.preview.isChecked())
  137. def onDebug(self):
  138. self.parent.webkitview.toggleDocClass('debug', self.debug.isChecked())
  139. def onGrid(self):
  140. self.parent.webkitview.toggleDocClass('grid', self.grid.isChecked())
  141. def onSpread(self):
  142. self.parent.webkitview.toggleDocClass('spread', self.spread.isChecked())
  143. def onReload(self):
  144. print("onReload")
  145. # self.parent.webkitview.
  146. def onGenPDF(self):
  147. print("onGenPDF")
  148. self.parent.webkitview.ongenPDF()
  149. class CodeEditor(QPlainTextEdit):
  150. def __init__(self, core, tabs, file, mode):
  151. super(CodeEditor, self).__init__()
  152. self.core = core
  153. self.tabs = tabs
  154. self.file = file
  155. self.setText()
  156. self.setTabStopWidth(15)
  157. self.hl= highlighter.Highlighter(self.document(),mode)
  158. self.shortcut = QShortcut(QKeySequence("Ctrl+s"), self)
  159. self.shortcut.activated.connect(self.save)
  160. def setText(self):
  161. try:
  162. self.textChanged.disconnect(self.onTextChanged)
  163. except Exception as e:
  164. print(e)
  165. self.filepath = os.path.join(self.core.cwd,self.file)
  166. self.clear()
  167. self.insertPlainText(open(self.filepath, 'r').read())
  168. self.changed = False
  169. self.textChanged.connect(self.onTextChanged)
  170. font = QFont()
  171. font.setFamily("Droid Sans Mono")
  172. font.setFixedPitch(True)
  173. font.setPointSize(12)
  174. self.setFont(font)
  175. # self.highlighter = Highlighter(self.document())
  176. # https://pypi.python.org/pypi/QScintilla/2.9.2
  177. def onTextChanged(self):
  178. # print('textChanged')
  179. # print(self.toPlainText())
  180. # open(self.filepath, 'w').write(self.toPlainText())
  181. if not self.changed:
  182. self.changed = True
  183. i = self.tabs.currentIndex()
  184. self.tabs.setTabText(i, "* "+self.tabs.tabText(i))
  185. # TODO: indicate that webview needs to be reloaded
  186. def save(self):
  187. if self.changed:
  188. open(self.filepath, 'w').write(self.toPlainText())
  189. i = self.tabs.currentIndex()
  190. self.tabs.setTabText(i, re.sub(r'^\*\s', '', self.tabs.tabText(i)))
  191. self.changed = False
  192. # TODO: how to combine file save and project save
  193. class Editor(QWidget):
  194. def __init__(self, parent, core):
  195. super(Editor, self).__init__()
  196. self.core = core
  197. self.layout = QVBoxLayout(self)
  198. self.layout.setContentsMargins(0,0,0,0)
  199. # Initialize tab screen
  200. self.tabs = QTabWidget()
  201. self.scsstab = CodeEditor(core, self.tabs, 'assets/css/styles.scss', "scss")
  202. self.jstab = CodeEditor(core, self.tabs, 'assets/js/script.js', 'js')
  203. # Add tabs
  204. self.tabs.addTab(self.scsstab,"scss")
  205. self.tabs.addTab(self.jstab,"js")
  206. # Add tabs to widget
  207. self.layout.addWidget(self.tabs)
  208. self.setLayout(self.layout)
  209. def refresh(self):
  210. self.scsstab.setText()
  211. self.jstab.setText()
  212. class DesignStack(QWidget):
  213. def __init__(self, core):
  214. super(DesignStack, self).__init__()
  215. # self.grid = QGridLayout()
  216. self.hbox = QHBoxLayout()
  217. self.hbox.setContentsMargins(0,0,0,0)
  218. self.setLayout(self.hbox)
  219. self.webview = QWidget()
  220. self.webview.vbox = QVBoxLayout()
  221. self.webview.setLayout(self.webview.vbox)
  222. self.webview.vbox.setContentsMargins(0,0,0,0)
  223. self.webkitview = WebkitView(self, core)
  224. self.webkitinspector = WebkitInspector(self, self.webkitview)
  225. shortcut = QShortcut(self)
  226. shortcut.setKey("F12")
  227. shortcut.activated.connect(self.toggleInspector)
  228. self.webkitinspector.setVisible(False)
  229. self.webviewtoolbar = WebViewToolBar(self)
  230. self.webview.vbox.addWidget(self.webviewtoolbar)
  231. self.vsplitter = QSplitter(QtCore.Qt.Vertical)
  232. self.vsplitter.addWidget(self.webkitview)
  233. self.vsplitter.addWidget(self.webkitinspector)
  234. self.vsplitter.splitterMoved.connect(self.movedSplitter)
  235. self.webview.vbox.addWidget(self.vsplitter)
  236. self.hsplitter = QSplitter(QtCore.Qt.Horizontal)
  237. self.hsplitter.addWidget(self.webview)
  238. self.editor = Editor(self, core)
  239. self.hsplitter.addWidget(self.editor)
  240. self.hsplitter.splitterMoved.connect(self.movedSplitter)
  241. self.hbox.addWidget(self.hsplitter)
  242. self.restorePrefs()
  243. def toggleInspector(self):
  244. self.webkitinspector.setVisible(not self.webkitinspector.isVisible())
  245. def restorePrefs(self):
  246. settings = QSettings('FiguresLibres', 'Cascade')
  247. print(settings.value('design/vsplitter/sizes', self.vsplitter.sizes()))
  248. vals = settings.value('design/vsplitter/sizes', None)
  249. if vals:
  250. sizes = []
  251. for size in vals: sizes.append(int(size))
  252. self.vsplitter.setSizes(sizes)
  253. vals = settings.value('design/hsplitter/sizes', None)
  254. if vals:
  255. sizes = []
  256. for size in vals: sizes.append(int(size))
  257. self.hsplitter.setSizes(sizes)
  258. def movedSplitter(self):
  259. settings = QSettings('FiguresLibres', 'Cascade')
  260. # print(self.vsplitter.sizes())
  261. settings.setValue('design/vsplitter/sizes', self.vsplitter.sizes())
  262. settings.setValue('design/hsplitter/sizes', self.hsplitter.sizes())
  263. def refresh(self):
  264. self.editor.refresh()
  265. self.webkitview.refresh()