design.py 12 KB

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