diff --git a/app.py b/app.py index c7f863f..ddc906e 100755 --- a/app.py +++ b/app.py @@ -22,11 +22,12 @@ from PyQt5.QtWebKitWidgets import QWebPage, QWebView, QWebInspector import json import git -from classes import server, compiler, design, content +from classes import server, sasscompiler, design, content class Core(): def __init__(self, parent=None): # restore previous preferences + self.appcwd = os.getcwd() self.restorePreferences() self._mw = False @@ -34,13 +35,15 @@ class Core(): # print(self.temp) self.tempcwd = False + # if ther's not current project folder from restorepref + # initaite a new temp project if(self.cwd == None or not os.path.isdir(self.cwd)): self.cwd = os.path.join(self.temp, 'cwd') self.tempcwd = True self.initnewproject() - self.server = server.Server(self.temp) - self.compiler = compiler.Compiler(self.temp) + self.server = server.Server(self) + self.sasscompiler = sasscompiler.Compiler(self) @property def mainwindow(self): @@ -61,6 +64,8 @@ class Core(): # print(settings.allKeys()) self.cwd = settings.value('core/cwd', None) + self.dialog_path = settings.value('core/dialog_path', os.path.expanduser('~')) + self.mw_size = settings.value('mainwindow/size', QtCore.QSize(1024, 768)) self.mw_pos = settings.value('mainwindow/pos', QtCore.QPoint(0, 0)) self.mw_curstack = int(settings.value('mainwindow/curstack', 0)) @@ -74,6 +79,8 @@ class Core(): if not self.tempcwd: settings.setValue('core/cwd', self.cwd) + settings.setValue('core/dialog_path', self.dialog_path) + settings.setValue('mainwindow/size', self._mw.size()) settings.setValue('mainwindow/pos', self._mw.pos()) settings.setValue('mainwindow/curstack', self._mw.mainstack.currentIndex()) @@ -82,7 +89,7 @@ class Core(): if cwd == None : cwd = self.cwd else : - self.cwd = cwd + self.changeCWD(cwd) shutil.copytree('templates/newproject', cwd) self.prefs = json.loads(open(os.path.join(cwd,'.config/prefs.json')).read()) @@ -94,11 +101,17 @@ class Core(): # TODO: embed project styles.scss to app scss frame work def saveproject(self, cwd = None): - if not cwd == None and self.tempcwd: + if not cwd == None: shutil.copytree(self.cwd, cwd) - self.cwd = cwd self.tempcwd = False - self._mw.setWindowTitle("Cascade – "+self.cwd) + self.changeCWD(cwd) + + def changeCWD(self, cwd): + self.cwd = cwd + self.server.reload() + self.sasscompiler.reload() + # if not self.tempcwd: + self._mw.setWindowTitle("Cascade – "+self.cwd) def quit(self): self.savePreferences() @@ -113,7 +126,7 @@ class MainWindow(QMainWindow): self.core = core self.setWindowTitle("Cascade") - self.setWindowIcon(QIcon('assets/images/icon.png')) + self.setWindowIcon(QIcon(os.path.join(self.core.appcwd,'assets/images/icon.png'))) self.resize(self.core.mw_size) self.move(self.core.mw_pos) @@ -140,8 +153,6 @@ class MainWindow(QMainWindow): self.save_action = QAction("&Save Project as",self) self.save_action.setShortcut("Ctrl+Shift+s") file.addAction(self.save_action) - # if not self.core.tempcwd: - # self.save_action.setEnabled(False) quit = QAction("&Quit",self) quit.setShortcut("Ctrl+q") @@ -151,12 +162,19 @@ class MainWindow(QMainWindow): # edit menu edit = bar.addMenu("&Edit") - edit.addAction("©") - edit.addAction("&paste") + # edit.addAction("©") + # edit.addAction("&paste") edit.addAction("&build") - edit.addAction("&reload") + + self.reload_action = QAction("&Reload",self) + self.reload_action.setShortcut("Ctrl+r") + edit.addAction(self.reload_action) + edit.addAction("&preferences") + edit.triggered[QAction].connect(self.oneditmenutrigger) + + # view menu view = bar.addMenu("&View") @@ -194,30 +212,49 @@ class MainWindow(QMainWindow): print("open") def newprojectdialogue(self): - projectname = QFileDialog.getSaveFileName(self, 'New Project', '') + dialog = QFileDialog() + dialog.setFileMode(QFileDialog.Directory) + dialog.setAcceptMode(QFileDialog.AcceptOpen) + projectname = dialog.getSaveFileName( + self, + 'New Project', + self.core.dialog_path + )[0] # TODO: no file type try: - if not os.path.isdir(projectname[0]): - self.core.initnewproject(projectname[0]) + head, tail = os.path.split(projectname) + self.core.dialog_path = head + if not os.path.isdir(projectname): + self.core.initnewproject(projectname) else: print("folder already exists") # TODO: check if is cascade folder except Exception as e: + print('Exception', e) pass def saveprojectdialogue(self, quit=False): - projectname = QFileDialog.getSaveFileName(self, 'Save Project', '') + dialog = QFileDialog() + dialog.setFileMode(QFileDialog.Directory) + dialog.setAcceptMode(QFileDialog.AcceptOpen) + projectname = dialog.getSaveFileName( + self, + 'Save Project', + self.core.dialog_path + )[0] # TODO: no file type try: - if not os.path.isdir(projectname[0]): - self.core.saveproject(projectname[0]) - # self.save_action.setEnabled(False) + head, tail = os.path.split(projectname) + self.core.dialog_path = head + if not os.path.isdir(projectname): + self.core.saveproject(projectname) if quit: self.quit() else: print("folder already exists") # TODO: check if is cascade folder except Exception as e: + print('Exception', e) pass def quit(self): @@ -231,6 +268,13 @@ class MainWindow(QMainWindow): else: self.core.quit() + + def oneditmenutrigger(self, q): + print(q.text()+" is triggered") + if q.text() == "&Reload": + self.designstack.webkitview.reload() + + def onviewmenutrigger(self, q): print(q.text()+" is triggered") if q.text() == "&Design": diff --git a/assets/js/script.js b/assets/js/script.js deleted file mode 100644 index c57a03c..0000000 --- a/assets/js/script.js +++ /dev/null @@ -1,68 +0,0 @@ -jQuery(document).ready(function($) { - - console.log("Hello Les notices"); - - // $('.story-page').each(function(index, el) { - // $figures = $('figure', this); - // $(this).addClass("figures-"+$figures.length); - // }); - - $('.story-page-2 h2, .story-page:not(.story-page-0):not(.story-page-1):not(.story-page-2) h1').each(function(index, el) { - // console.log("item to typotize",$(this).text()); - var chars = $(this).text().split(""); - // console.log("chars", chars); - var typotized = ""; - var k = 0; - for (var j = 0; j < chars.length; j++) { - // console.log('node '+j+" modulo : "+(j % 6),chars[j]); - if(! /\s/.test(chars[j]) ){ - k++; - if ( k % 12 == 0){ - typotized += ''+chars[j]+''; - continue; - } - if ( k % 9 == 0){ - typotized += ''+chars[j]+''; - continue; - } - if ( k % 6 == 0){ - typotized += ''+chars[j]+''; - continue; - } - if ( k % 3 == 0){ - typotized += ''+chars[j]+''; - continue; - } - } - typotized += chars[j]; - } - $(this).html(typotized); - }); - -/* - // Detect if a flow element is in odd or even paper - - // var flow = document.webkitGetFlowByName('flow-main'); - // var flow = NamedFlowMap;//();//getFlowByName("flow-main"); - // console.log('flow', window); - var namedFlow = document.webkitGetNamedFlows()["flow-main"]; - console.log(namedFlow); - // var regions = namedFlow.getRegions(); - // var content = namedFlow.getContent(); - - setTimeout(function(){ - var region, paper, paperid; - $(".story-page>h1,.story-page>figure", "#flow-main").each(function(index, el) { - region = namedFlow.getRegionsByContent(this); - // paper = $(region).parents('.paper'); - paperid = $(region).parents('.paper').attr('id').match(/page-(\d+)/)[1]; - // console.log(paperid); - if(paperid % 2 == 0){ - $(this).addClass('paper-odd') - }else{ - $(this).addClass('paper-even') - } - }); - }, 1000); -*/ -}); diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss deleted file mode 100644 index 1d16921..0000000 --- a/assets/scss/styles.scss +++ /dev/null @@ -1,297 +0,0 @@ -// your styles here - -$bgcolor:white; - -.paper, .preview .page { - overflow: hidden; - background-color: $bgcolor; -} - - -#stories{ - font-family: "Vremena Grotesk" sans-serif; -} - -.story-page{ - @extend .w9; - // -webkit-region-break-after:always; - // break-after:always; - // -webkit-region-break-inside:auto; - // region-break-inside: auto; - // -webkit-region-fragment: break; - -} - -.story-page-0, -.story-page-1, -.story-page-2{ - @extend .h12; - // overflow: visible; - // position: relative; - -webkit-region-break-after:always; - break-after:always; - -webkit-region-break-inside: avoid; - break-inside: avoid; -} - - - -figure, img{ - margin:0; padding:0; - max-width: 100%; -} - -// footer / pagination -.paper { - .body:before, .body:after{ - // display: block; - display:inline-block; - width:auto; - .debug &{ - outline: 1px solid green; - } - } - .body:before{ - top:50%; - width:50mm; - margin-top: -25mm; - text-align: center; - } - .body:after{ - bottom:-5mm; - width:15mm; - } -} -// Footer -/*gauche*/ -.paper:nth-child(odd) .body:before { - transform-origin: right; - transform: rotateZ(-90deg); - right:-7mm; -} -/*droite*/ -.paper:nth-child(even) .body:before { - transform-origin: left; - transform: rotateZ(90deg); - left:-7mm; -} - -// Pagination -// gauche -.paper:nth-child(odd) .body:after{ - text-align: right; - right:-8mm; -} -// droite -.paper:nth-child(even) .body:after{ - text-align: left; - left:-8mm; -} - - -#page-1, #page-2{ - .body:before, .body:after{ - display: none; - } - .body{ - top:0; right:0; bottom:0; left:0; - } - .bloc{ - top:0; right:0; bottom:0; left:0; - } -} - - -.story-page-0, .story-page-1{ - width:100%; - height:100%; - h1{ - margin:0 auto; - width:mm2pt(150); - font-family: 'Vremena Grotesk'; - font-weight: 500; - font-size: 95pt; - text-transform: uppercase; - text-align: center; - line-height: 1.4; - letter-spacing: 0.2em; - -webkit-region-break-inside:avoid; - break-inside:avoid; - - } -} -.story-page-0{ - h1{ - transform: translateX(4mm) translateY(-13mm); - } -} -.story-page-1{ - h1{ - transform: translateX(-65mm) translateY(-20mm); - } -} - - -.story-page-2{ - height:auto; - h2{ - text-align: center; - font-family: "Vremena"; - font-size: 25pt; - font-weight: 400; - padding-top:mm2pt(55); - padding-left: 2.8em; - padding-right: 2.8em; - } -} - -.typo-1{ - font-family: "Fantasque"; - font-weight: bold; - font-style: italic; -} -.typo-2{ - font-family: "Vremena"; -} -.typo-3{ - font-family: "Vremena Grotesk"; - font-weight: bold; -} -.typo-4{ - font-family: "Gap Sans" -} - -.story-page{ - margin-bottom: 10mm; -} - -.story-page:not(.story-page-0):not(.story-page-1):not(.story-page-2){ - h1{ - // -webkit-region-break-before: auto; - -webkit-region-break-inside: avoid; - -webkit-region-break-after: avoid; - - margin: 0 0 5mm 0; - margin-right: -$page-margin-inside*0.5; - - font-size: 40pt; - font-weight: normal; - line-height: 35pt; - - // &.paper-odd{ - text-align: right; - padding-left: 20mm; - // } - &.paper-even{ - text-align: left; - padding-left: 0; - padding-right: 20mm; - margin: 0 0 5mm 0; - margin-left: -$page-margin-inside*0.5; - } - } - - figure{ - // -webkit-region-break-before: avoid; - -webkit-region-break-inside: avoid; - // -webkit-region-break-after: avoid; - - position: relative; - - $iw:35mm; // image width - $bw:4pt; // border width - - max-width: $iw+$bw*3; - - img{ - max-width: $iw; - border:$bw solid black; - border-left: $bw*2 solid black; - } - - figcaption{ - font-size: 8pt; - line-height: 9.5pt; - max-width: 100%; - padding-left: $bw*2; - } - - // &.paper-odd{ - float: left; - margin:0 4mm 2mm 0; - margin-left: -$page-margin-outside - $bw; - // } - &.paper-even{ - float: right; - margin:0 0 2mm 4mm; - margin-right: -$page-margin-outside - $bw; - text-align: right; - - img{ - border:$bw solid black; - border-right: $bw*2 solid black; - } - - figcaption{ - padding-right: $bw*2; - } - } - - } - - p{ - font-family: "Averia Serif"; - font-size: 9pt; - line-height: 13pt; - margin-top: 0; - -webkit-hyphens: auto; - // -webkit-region-break-before: always; - // -webkit-region-break-inside: auto; - // -webkit-region-break-after: always; - // &:nth-of-type(1){ - // -webkit-region-break-before:avoid; - // -webkit-region-break-inside:auto; - // } - } - - &:after{ - content: ""; - display: block; - float: none; - clear: both; - } -} -/* -@-webkit-region .paper .flow-main { - h1{ - // color: red!important; - } -} - -@-webkit-region .paper:nth-child(even) .flow-main { - h1{ - color: purple; - text-align: right; - padding-left: 3mm; - } - figure{ - float: left; - margin-left: -$page-margin-outside; - margin:0 4mm 2mm 0; - } -} - - -@-webkit-region .paper:nth-child(odd) .flow-main { - h1{ - color: blue; - text-align: left; - padding-right: 3mm; - } - figure{ - float: right; - margin-left: -$page-margin-outside; - margin:0 0 2mm 4mm; - } -} -*/ diff --git a/classes/compiler.py b/classes/compiler.py deleted file mode 100644 index a76f336..0000000 --- a/classes/compiler.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -from PyQt5.QtCore import QFileSystemWatcher -import sass - -class Compiler(): - def __init__(self,parent=None): - paths = [ - 'assets', - 'assets/scss', - 'assets/scss/styles.scss' - ] - self.fs_watcher = QFileSystemWatcher(paths) - # self.fs_watcher.directoryChanged.connect(self.directory_changed) - self.fs_watcher.fileChanged.connect(self.compile_scss) - self.compile_scss() - - # def directory_changed(path): - # print("Directory changed : %s" % path) - - def compile_scss(path = ""): - print("compiling sass : %s" % path) - scss = sass.compile_file(b'assets/scss/main.scss') - with open('assets/scss/main.css', 'w') as fp: - fp.write(scss.decode('utf8')) diff --git a/classes/content.py b/classes/content.py index a33d83d..fd853bb 100644 --- a/classes/content.py +++ b/classes/content.py @@ -24,8 +24,8 @@ class Summary(QWidget): super(Summary, self).__init__(parent) self.parent = parent - self.jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json') - sum_json = open(self.jsonfilepath).read() + jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json') + sum_json = open(jsonfilepath).read() self.sum = json.loads(sum_json) vbox = QVBoxLayout() @@ -43,13 +43,14 @@ class Summary(QWidget): # file filename = re.sub(r'\W', "_", text)+".md" # TODO: check if file does not already exists - filepath = os.path.join(self.core.cwd,'contents',filename) + filepath = os.path.join(self.parent.core.cwd,'contents',filename) with open(filepath, 'w') as fp: fp.write('#'+text) # json item = {"title":text,"file":filename} self.sum.append(item) - with open(self.jsonfilepath, "w") as fp: + jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json') + with open(jsonfilepath, "w") as fp: json.dump(self.sum, fp, ensure_ascii=False, indent="\t") # refresh list self.list.addNewItem(item) @@ -59,11 +60,12 @@ class Summary(QWidget): newdata = [] for i in range(0,self.list.count()): # print(self.item(i).item['title']) - newdata.append(self.list.item(i).item) + newdata.append(self.list.item(i).data) # print(newdata) self.sum = newdata - with open(self.jsonfilepath, "w") as fp: + jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json') + with open(jsonfilepath, "w") as fp: json.dump(newdata, fp, ensure_ascii=False, indent="\t") diff --git a/classes/design.py b/classes/design.py index e22314f..f5ae3ac 100644 --- a/classes/design.py +++ b/classes/design.py @@ -25,6 +25,7 @@ class WebkitInspector(QWebInspector): super(WebkitInspector, self).__init__(parent) self.webkitview = webkitview self.setPage(self.webkitview.page()) + self.showMaximized() # TODO: webkitinspector is disappearing when chaging tabs @@ -73,7 +74,7 @@ class Editor(QWidget): # Initialize tab screen self.tabs = QTabWidget() - self.scsstab = CodeEditor(core, self.tabs, 'assets/scss/styles.scss') + self.scsstab = CodeEditor(core, self.tabs, 'assets/css/styles.scss') self.jstab = CodeEditor(core, self.tabs, 'assets/js/script.js') # Add tabs @@ -153,6 +154,6 @@ class DesignStack(QWidget): def movedSplitter(self): settings = QSettings('FiguresLibres', 'Cascade') - print(self.vsplitter.sizes()) + # print(self.vsplitter.sizes()) settings.setValue('design/vsplitter/sizes', self.vsplitter.sizes()) settings.setValue('design/hsplitter/sizes', self.hsplitter.sizes()) diff --git a/classes/sasscompiler.py b/classes/sasscompiler.py new file mode 100644 index 0000000..ff3db21 --- /dev/null +++ b/classes/sasscompiler.py @@ -0,0 +1,43 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os +from PyQt5.QtCore import QFileSystemWatcher +import sass + +class Compiler(): + def __init__(self,parent): + self.parent = parent + self.initWatching() + self.compile_scss() + # def directory_changed(path): + # print("Directory changed : %s" % path) + + def initWatching(self): + self.refreshPaths() + self.fs_watcher = QFileSystemWatcher(self.paths) + # self.fs_watcher.directoryChanged.connect(self.directory_changed) + self.fs_watcher.fileChanged.connect(self.compile_scss) + + def compile_scss(self): + print("compiling sass") + try: + scss = sass.compile_file(str.encode(os.path.join(self.parent.cwd,'assets/css/main.scss'))) + with open(os.path.join(self.parent.cwd,'assets/css/main.css'), 'w') as fp: + fp.write(scss.decode('utf8')) + except Exception as e: + print("Error compiling Sass", e) + pass + + + def refreshPaths(self): + self.paths = [ + os.path.join(self.parent.cwd,'assets'), + os.path.join(self.parent.cwd,'assets/css'), + os.path.join(self.parent.cwd,'assets/css/styles.scss') + ] + + def reload(self): + self.fs_watcher.removePaths(self.paths) + self.refreshPaths() + self.fs_watcher.addPaths(self.paths) diff --git a/classes/server.py b/classes/server.py index 27132e6..d0a1654 100644 --- a/classes/server.py +++ b/classes/server.py @@ -13,8 +13,9 @@ import threading class Server(): - def __init__(self, parent=None): + def __init__(self, parent): + self.parent = parent # find free port sock = socket() sock.bind(('', 0)) @@ -22,13 +23,24 @@ class Server(): self._port = sock.getsockname()[1] sock.close() - self.httpd = http.server.HTTPServer(('', self.port), http.server.SimpleHTTPRequestHandler) - self.thread = threading.Thread(target=self.httpd.serve_forever) + # self.initial_cwd = os.getcwd() + self.thread = threading.Thread(target=self.webserver) self.thread.daemon = True self.thread.start() - print("serving at port", self._port) + # os.chdir(self.initial_cwd) + def webserver(self): + os.chdir(self.parent.cwd) + self.httpd = http.server.HTTPServer(('', self.port), http.server.SimpleHTTPRequestHandler) + self.httpd.serve_forever() + print("serving at port", self._port) @property def port(self): return self._port + + def reload(self): + # self.thread.shutdown() + os.chdir(self.parent.cwd) + # self.thread.start() + # os.chdir(self.initial_cwd) diff --git a/assets/scss/debug.scss b/templates/newproject/assets/css/debug.scss similarity index 100% rename from assets/scss/debug.scss rename to templates/newproject/assets/css/debug.scss diff --git a/assets/scss/grid.scss b/templates/newproject/assets/css/grid.scss similarity index 100% rename from assets/scss/grid.scss rename to templates/newproject/assets/css/grid.scss diff --git a/assets/scss/html2print.scss b/templates/newproject/assets/css/html2print.scss similarity index 100% rename from assets/scss/html2print.scss rename to templates/newproject/assets/css/html2print.scss diff --git a/assets/scss/layout.scss b/templates/newproject/assets/css/layout.scss similarity index 100% rename from assets/scss/layout.scss rename to templates/newproject/assets/css/layout.scss diff --git a/assets/scss/main.scss b/templates/newproject/assets/css/main.scss similarity index 100% rename from assets/scss/main.scss rename to templates/newproject/assets/css/main.scss diff --git a/assets/scss/mixins.scss b/templates/newproject/assets/css/mixins.scss similarity index 100% rename from assets/scss/mixins.scss rename to templates/newproject/assets/css/mixins.scss diff --git a/templates/newproject/assets/scss/styles.scss b/templates/newproject/assets/css/styles.scss similarity index 100% rename from templates/newproject/assets/scss/styles.scss rename to templates/newproject/assets/css/styles.scss diff --git a/assets/js/html2print.js b/templates/newproject/assets/js/html2print.js similarity index 100% rename from assets/js/html2print.js rename to templates/newproject/assets/js/html2print.js diff --git a/assets/js/setup.js b/templates/newproject/assets/js/setup.js similarity index 100% rename from assets/js/setup.js rename to templates/newproject/assets/js/setup.js diff --git a/assets/lib/css-regions-polyfill.min.js b/templates/newproject/assets/lib/css-regions-polyfill.min.js similarity index 100% rename from assets/lib/css-regions-polyfill.min.js rename to templates/newproject/assets/lib/css-regions-polyfill.min.js diff --git a/assets/lib/jquery.min.js b/templates/newproject/assets/lib/jquery.min.js similarity index 100% rename from assets/lib/jquery.min.js rename to templates/newproject/assets/lib/jquery.min.js diff --git a/index.html b/templates/newproject/index.html similarity index 77% rename from index.html rename to templates/newproject/index.html index 2c19d3c..82f0d72 100644 --- a/index.html +++ b/templates/newproject/index.html @@ -3,7 +3,7 @@