Python ebook maker (updates page)

03/10/2019 – updated to v. 1.5 (menubar)

04/10/2019 – updated to v. 1.5 (highlight code)

What is this?

This is a little project to show some tkinter features, but it can be also used to make something interesting. You can create different txt files from the app, edit the text, change their names, delete them, having the different files in a list on the right of the app and you can also convert them into an html page with all the text in the different files or a html page with the text of a single page. It accept plain text to wich you can add some symbols at the beginning of a line to make some sort of markup or use html tags directly. I am actually using it and I will add new features (like committing the files to a github repository as you save the files) in the future.

Version 1.4c2

In version 1.42c3-user-edition added the ctrl+p to save the html page of a single txt file

Download it in the githun repository.

Final version post

Organize a complex ebook in simple txt files, add html tags and images with special characters, from simple txt files. This is the aim of this app. Another aim is to get better at knowing tkinter’s widgets and how to start making a GUI, from skratch. This is PyEbooksMaker or Python Ebooks Maker.

In the last days we have seen how to make a sort of ebook maker, to organize our work with a simple app and then create an html file with all the work that could easily become an true ebook. There is an update to the final version with many new features, like you can see in the the following paragraph.

New features

I added some new features to the app:

  • rename files (with the button or pressing F2)
  • delete files
  • chance to insert
    • H2 tag with *
    •  H3 tag with ^
    • images with # tag

So, now, it is almost a complete app, even if it is very rough and need to be refined.

This is the code, until now,:

# pyem_1_4c2 - 25/09/2019 @ Giovanni Gatto
# pyem_1_4c3_user_edition_26_set_2019_compiti
# aggiunto ctrl+p per visualizza la singola pagina html generata
# (si poteva fare col pulsante save page)

import tkinter as tk
import glob
from time import sleep
import os
"""
1.2
Added ctrl+s <Control+s> to bind of text
Added label to editor
1.3
added red symbol for rendering html
1.4
Added way to save render single txt file
"""

class Ebook:
    def __init__(self, root):
        """Define window for the app"""
        self.root = root
        self.root.geometry("850x400")
        self.root["bg"] = "coral"
        self.menu()
        self.editor()
        self.root.bind("<Control-b>", lambda x: self.save_ebook())

    # Widgets on the left ===============|
    def menu(self):
        """Listbox on the left with file names"""

        self.menubar = tk.Menu(self.root)
        self.menubar.add_command(label="Help", command=self.help)
        self.root.config(menu=self.menubar)

        self.frame2 = tk.Frame(self.root)
        self.frame2["bg"] = "coral"
        self.frame2.pack(side='left', fill=tk.Y)

        self.button = tk.Button(self.frame2, text="Save", command = self.save)
        self.button.pack()
        self.button_ebook = tk.Button(self.frame2, text="Save ebook", command = self.save_ebook)
        self.button_ebook.pack()

        # Save only current page
        self.button_page = tk.Button(self.frame2, text="Save page", command = self.save_page)
        self.button_page.pack()

        # commit to git
        # self.button_commit = tk.Button(self.frame2, text="Commit", command = self.commit)
        # self.button_commit.pack()

        self.button_plus = tk.Button(self.frame2, text="+", command =lambda: self.new_window(Win1))
        self.button_plus.pack()

        self.button_rename = tk.Button(self.frame2, text = "Rename file",
            command= lambda: self.new_window(Rename))
        self.button_rename.pack()

        self.button_delete = tk.Button(self.frame2, text = "delete file",
            command= lambda: self.delete_file())
        self.button_delete.pack()

        self.lab_help = tk.Label(self.frame2, text="Symbols:\n-------\n* = <h2>\n^ = <h3>\n# = <img...\n=> = red\n<F2> Rename", bg="coral")
        self.lab_help.pack()

        self.frame1 = tk.Frame(self.root)
        self.frame1["bg"] = "coral"
        self.frame1.pack(side='left', fill=tk.Y)
        self.lstb = tk.Listbox(self.frame1, width=30) # selectmode='multiple', exportselection=0)
        self.lstb['bg'] = "black"
        self.lstb['fg'] = 'gold'
        self.lstb.pack(fill=tk.Y, expand=1)
        self.lstb.bind("<<ListboxSelect>>", lambda x: self.show_text_in_editor())
        self.lstb.bind("<F2>", lambda x: self.new_window(Rename))
        self.files = glob.glob("text\\*.txt")

        for file in self.files:
            self.lstb.insert(tk.END, file)

    def new_window(self, _class):
        self.new = tk.Toplevel(self.root)
        _class(self.new)

    def commit(self):
        os.startfile("commit.bat")

    def help(self):
        print("Press <F2> to rename files")

    
    def rename(self, filename):

        os.rename(self.filename, "text\\" + filename)
        self.files = glob.glob("text\\*.txt")
        self.lstb.delete("active")
        self.lstb.insert(self.files.index("text\\" + filename), "text\\" + filename)

    def new_chapter(self, filename):
        self.new.destroy()
        if not filename.endswith(".txt"):
            filename += ".txt"
        #os.chdir("text")
        with open("text\\" + filename, "w", encoding="utf-8") as file:
            file.write("")
        self.reload_list_files(filename)

    def reload_list_files(self, filename=""):
        #os.chdir("..")
        self.lstb.delete(0, tk.END)
        self.files = [f for f in glob.glob("text\\*txt")]
        for file in self.files:
            self.lstb.insert(tk.END, file)
        self.lstb.select_set(self.files.index("text\\" + filename))

    def reload_list_files_delete(self, filename=""):
        #os.chdir("..")
        self.lstb.delete(0, tk.END)
        self.files = [f for f in glob.glob("text\\*txt")]
        for file in self.files:
            self.lstb.insert(tk.END, file)

    def delete_file(self):
        for num in self.lstb.curselection():
            os.remove(self.files[num])
        self.reload_list_files_delete()

    def save(self):
        if self.text.get("1.0", tk.END) != "":
            with open(self.filename, "w", encoding="utf-8") as file:
                file.write(self.text.get("1.0", tk.END))
            self.label_file_name["text"] += "...saved"

    def save_ebook(self):
        html = ""
        with open("ebook.html", "w", encoding="utf-8") as htmlfile:
            for file in self.files: # this is the name of each file
                with open(file, "r", encoding="utf-8") as singlefile:
                    # ================= SYMBOL => HTML ==============
                    html += self.html_convert(singlefile.read())
            htmlfile.write(html)
        self.label_file_name["text"] += "...Opening Ebook"
        os.startfile("ebook.html")

    def save_page(self):
        """Save a single page v. 1.4 23/09/2019 at 05:40"""
        html = ""
        current = self.lstb.get(tk.ACTIVE)[:-4] # The file selected without .txt
        with open(f"{current}.html", "w", encoding="utf-8") as htmlfile:
            # opend the active (selected) item in the listbox
            with open(f"{current}.txt", "r", encoding="utf-8") as readfile:
                read = readfile.read() # get the text of the active file
                read = self.html_convert(read) # convert this text in html with *^=>
                htmlfile.write(read) # create the new file with the rendered text
        self.label_file_name["text"] += "...page rendered"
        os.startfile(f"{current}.html")
        # os.system("start ../index.html")



    def html_convert(self, text_to_render):
        """Convert to my Markup language"""
        html = ""
        text_to_render = text_to_render.split("\n")

        for line in text_to_render:
            if line != "":
                if line[0] == "*":
                    line = line.replace("*","")
                    html += f"<h2>{line}</h2>"
                elif line[0] == "^":
                    line = line.replace("^","")
                    html += f"<h3>{line}</h3>"
                elif line[0] == "#":
                    line = line.replace("#","")
                    if line.startswith("http"):
                        html += f"<img src='{line}' width='100%'><br>"
                    else:                
                        html += f"<img src='img\\{line}' width='100%'><br>"
                elif line[0] == "=" and line[1]== ">":
                    line = line.replace("=>", "")
                    html += f"<span style='color:red'>{line}</span>"
                else:
                    html += f"<p>{line}</p>"
        return html

    def show_text_in_editor(self):
        """Shows text of selected file in the editor"""
        if not self.lstb.curselection() is ():
            index = self.lstb.curselection()[0]
            self.filename = self.files[index] # instead of self.lstb.get(index)
            with open(self.filename, "r", encoding="utf-8") as file:
                content = file.read()
            self.text.delete("1.0", tk.END)
            self.text.insert(tk.END, content)
            self.label_file_name['text'] = self.filename

    def editor(self):
        """The text where you can write"""
        self.label_file_name = tk.Label(self.root, text="Editor - choose a file on the left")
        self.label_file_name.pack()
        self.text = tk.Text(self.root, wrap=tk.WORD)
        self.text['bg'] = "darkgreen"
        self.text['fg'] = 'white'
        self.text['font'] = "Arial 24"
        self.text.pack(fill=tk.Y, expand=1)
        self.text.bind("<Control-s>", lambda x: self.save())
        self.text.bind("<Control-p>", lambda x: self.save_page())


class Win1():
    def __init__(self, root):
        self.root = root
        self.root.geometry("300x100")
        self.root.title("Insert new file name")
        self.label_file_name = tk.Label(self.root, text="Enter a name")
        self.label_file_name.pack()
        self.entry = tk.Entry(self.root)
        self.entry.pack()
        self.entry.focus()
        self.entry.bind("<Return>", lambda x: app.new_chapter(self.entry.get()))

class Rename():
    def __init__(self, root):
        self.root = root
        self.root.geometry("300x100+200+200")
        self.root.title("Insert new file name")
        self.label_file_name = tk.Label(self.root, text="Enter a name")
        self.label_file_name.pack()
        self.entry_var = tk.StringVar()
        self.entry = tk.Entry(self.root, textvariable=self.entry_var)
        self.entry.pack()
        self.entry.focus()
        self.entry_var.set(app.filename.split("\\")[1])
        self.entry.bind("<Return>", lambda x: app.rename(self.entry.get()))


if __name__ == "__main__":
    # =============================== checks if folders exists &
                                   #= creates them if not
    if "text" in os.listdir():
        pass
    else:
        os.mkdir("text")

    if "img" in os.listdir():
        pass
    else:
        os.mkdir("img")

    root = tk.Tk()
    app = Ebook(root)
    app.root.title("pyem_1_4c3_user_edition_26_set_2019_compiti")
    root.mainloop()

Create a text folder inside the folder where this file is. Create also and img folder in case you want to add images using the initial tag # in the line with the image file name.

The video with the app working

Updates

1.42c3-user-edition

In version 1.42c3-user-edition added the ctrl+p to save the html page of a single txt file.

Update 1.4c2

Save single page

Now you can save a single page (save page button). This page will be rendered in html and saved by itself into the text directory. I am using this in case I want to render a single page to use without the whole ebook in a site or in any different ‘places’. There are some future features that I could implement and that I use to automatically add this pages into a site of github.io.

Future: Commit to github

This is related to what I wrote in the previous paragraph. If you want to use it for you, you must change the address of the repository, of course. You need to adapt the code to your needs. I will try to make it usable by others, but for now you can ignore it (the buttons are commented).

Images

Now you can use the # symbol to add Internet addresses of images and not only names of files stored into the img folder.

Update 1.3

22.09.16

  • creates folders text and img if not present
  • new symbol => for red color
  • ctrl + b shows the Ebook

Control if text and img folder are present, if not it creates them (in the if __name__ == “__main__ …”)

    if "text" in os.listdir():
        print("text folder exists")
    else:
        os.mkdir("text")
        print("text folder created")
    if "img" in os.listdir():
        print("img folder exists")
    else:
        os.mkdir("img")
        print("text folder created")

Added a new symbol “=>” that gives a red color to the text that follows it.

The code is in the method save_ebook

                        elif line[0] == "=" and line[1]== ">":
                            line = line.replace("=>", "")
                            html += f"<span style='color:red'>{line}</span>"

I added the instruction on the left

self.lab_help = tk.Label(self.frame2, text="Symbols:\n-------\n* = <h2>\n^ = <h3>\n# = <img...\n=> = red", bg="coral")

Now with ctrl + b you can create the ebook without using the button on the left.

This line of code does the job in the last line of the __init__ method of the class Ebook

        self.root.bind("<Control-b>", lambda x: self.save_ebook())

 

Update 1.2

22.09.2019 – Added the wrap = tk.Word to the arguments of

self.text = tk.Text(self.root, wrap=tk.WORD)

to make the words to to the next line without splitting them in a weird way.

Update 1.5

I added a menubar, instead of the buttons on the left side of the window.

        self.menubar = tk.Menu(self.root)
        self.menubar.add_command(label="[ + ]", command = lambda: self.new_window(Win1))
        self.menubar.add_command(label="[ Delete ]", command= lambda: self.delete_file())
        self.menubar.add_command(label="[ Rename ]", command= lambda: self.new_window(Rename))
        self.menubar.add_command(label="[ Page ]", command = self.save_page)
        self.menubar.add_command(label="[ Ebook ]", command = self.save_ebook)
        self.menubar.add_command(label="[ SAVE ]", command = self.save)       
        self.menubar.add_command(label="[ Help ]", command= lambda: self.new_window(Help))
        self.root.config(menu=self.menubar)

This is how the window looks now (prettier and with more space for the text and list of files).

The code of version 1.5

# pyem_1_4c2 - 25/09/2019 @ Giovanni Gatto
# pyem_1_4c3_user_edition_26_set_2019_compiti
# aggiunto ctrl+p per visualizza la singola pagina html generata
# (si poteva fare col pulsante save page)
# pyem2 - correct bug about renaming files
# pyem2b - added at 196 and commented 195 (because of can't find filename) 
            # self.filename = self.lstb.get(index)
# version 1.5 - added menubar
import tkinter as tk
import glob
from time import sleep
import os
"""
1.2
Added ctrl+s <Control+s> to bind of text
Added label to editor
1.3
added red symbol for rendering html
1.4
Added way to save render single txt file
"""

class Ebook:
    def __init__(self, root):
        """Define window for the app"""
        self.root = root
        self.root.geometry("850x400")
        self.root["bg"] = "coral"
        self.menu()
        self.editor()
        self.root.bind("<Control-b>", lambda x: self.save_ebook())

    # Widgets on the left ===============|
    def menu(self):
        """Listbox on the left with file names"""

        # commit to git
        # self.button_commit = tk.Button(self.frame2, text="Commit", command = self.commit)
        # self.button_commit.pack()

        self.menubar = tk.Menu(self.root)
        self.menubar.add_command(label="[ + ]", command = lambda: self.new_window(Win1))
        self.menubar.add_command(label="[ Delete ]", command= lambda: self.delete_file())
        self.menubar.add_command(label="[ Rename ]", command= lambda: self.new_window(Rename))
        self.menubar.add_command(label="[ Page ]", command = self.save_page)
        self.menubar.add_command(label="[ Ebook ]", command = self.save_ebook)
        self.menubar.add_command(label="[ SAVE ]", command = self.save)       
        self.menubar.add_command(label="[ Help ]", command= lambda: self.new_window(Help))
        self.root.config(menu=self.menubar)



        self.frame1 = tk.Frame(self.root)
        self.frame1["bg"] = "coral"
        self.frame1.pack(side='left', fill=tk.Y)
        self.lstb = tk.Listbox(self.frame1, width=30) # selectmode='multiple', exportselection=0)
        self.lstb['bg'] = "black"
        self.lstb['fg'] = 'gold'
        self.lstb.pack(fill=tk.Y, expand=1)
        self.lstb.bind("<<ListboxSelect>>", lambda x: self.show_text_in_editor())
        self.lstb.bind("<F2>", lambda x: self.new_window(Rename))
        self.files = glob.glob("text\\*.txt")

        for file in self.files:
            self.lstb.insert(tk.END, file)

    def new_window(self, _class):
        self.new = tk.Toplevel(self.root)
        _class(self.new)

    def commit(self):
        os.startfile("commit.bat")

    def help(self):
        print("Press <F2> to rename files")

    
    def rename(self, filename):
        self.lstb.delete("active")
        os.rename(self.filename, "text\\" + filename)
        self.files = glob.glob("text\\*.txt")
        self.reload_list_files(filename)
        # self.lstb.insert(self.files.index("text\\" + filename), "text\\" + filename)

    def new_chapter(self, filename):
        self.new.destroy()
        if not filename.endswith(".txt"):
            filename += ".txt"
        #os.chdir("text")
        with open("text\\" + filename, "w", encoding="utf-8") as file:
            file.write("")
        self.reload_list_files(filename)

    def reload_list_files(self, filename=""):
        #os.chdir("..")
        self.lstb.delete(0, tk.END)
        self.files = [f for f in glob.glob("text\\*txt")]
        for file in self.files:
            self.lstb.insert(tk.END, file)
        self.lstb.select_set(self.files.index("text\\" + filename))

    def reload_list_files_delete(self, filename=""):
        #os.chdir("..")
        self.lstb.delete(0, tk.END)
        self.files = [f for f in glob.glob("text\\*txt")]
        for file in self.files:
            self.lstb.insert(tk.END, file)

    def delete_file(self):
        for num in self.lstb.curselection():
            os.remove(self.files[num])
        self.reload_list_files_delete()

    def save(self):
        if self.text.get("1.0", tk.END) != "":
            with open(self.filename, "w", encoding="utf-8") as file:
                file.write(self.text.get("1.0", tk.END))
            self.label_file_name["text"] += "...saved"

    def save_ebook(self):
        html = ""
        with open("ebook.html", "w", encoding="utf-8") as htmlfile:
            for file in self.files: # this is the name of each file
                with open(file, "r", encoding="utf-8") as singlefile:
                    # ================= SYMBOL => HTML ==============
                    html += self.html_convert(singlefile.read())
            htmlfile.write(html)
        self.label_file_name["text"] += "...Opening Ebook"
        os.startfile("ebook.html")

    def save_page(self):
        """Save a single page v. 1.4 23/09/2019 at 05:40"""
        self.save()
        html = ""
        current = self.lstb.get(tk.ACTIVE)[:-4] # The file selected without .txt
        with open(f"{current}.html", "w", encoding="utf-8") as htmlfile:
            # opend the active (selected) item in the listbox
            with open(f"{current}.txt", "r", encoding="utf-8") as readfile:
                read = readfile.read() # get the text of the active file
                read = self.html_convert(read) # convert this text in html with *^=>
                htmlfile.write(read) # create the new file with the rendered text
        self.label_file_name["text"] += "...page rendered"
        os.startfile(f"{current}.html")
        # os.system("start ../index.html")



    def html_convert(self, text_to_render):
        """Convert to my Markup language"""
        html = ""
        text_to_render = text_to_render.split("\n")

        for line in text_to_render:
            if line != "":
                if line[0] == "*":
                    line = line.replace("*","")
                    html += f"<h2>{line}</h2>"
                elif line[0] == "^":
                    line = line.replace("^","")
                    html += f"<h3>{line}</h3>"
                elif line[0] == "§":
                    line = line.replace("§","")
                    if line.startswith("http"):
                        html += f"<img src='{line}' width='100%'><br>"
                    else:                
                        html += f"<img src='img\\{line}' width='100%'><br>"
                elif line[0] == "=" and line[1]== ">":
                    line = line.replace("=>", "")
                    html += f"<span style='color:red'>{line}</span>"
                else:
                    html += f"<p>{line}</p>"
        return html

    def show_text_in_editor(self):
        """Shows text of selected file in the editor"""
        
        if not self.lstb.curselection() is ():
            index = self.lstb.curselection()[0]
            #self.filename = self.files[index] # instead of self.lstb.get(index)
            self.filename = self.lstb.get(index)
            with open(self.filename, "r", encoding="utf-8") as file:
                content = file.read()
            self.text.delete("1.0", tk.END)
            self.text.insert(tk.END, content)
            self.label_file_name['text'] = self.filename

    def editor(self):
        """The text where you can write"""
        self.label_file_name = tk.Label(self.root, text="Editor - choose a file on the left")
        self.label_file_name.pack()
        self.text = tk.Text(self.root, wrap=tk.WORD)
        self.text['bg'] = "darkgreen"
        self.text['fg'] = 'white'
        self.text['font'] = "Arial 24"
        self.text.pack(fill=tk.Y, expand=1)
        self.text.bind("<Control-s>", lambda x: self.save())
        self.text.bind("<Control-p>", lambda x: self.save_page())


class Win1():
    def __init__(self, root):
        self.root = root
        self.root.geometry("300x100")
        self.root.title("Insert new file name")
        self.label_file_name = tk.Label(self.root, text="Enter a name")
        self.label_file_name.pack()
        self.entry = tk.Entry(self.root)
        self.entry.pack()
        self.entry.focus()
        self.entry.bind("<Return>", lambda x: app.new_chapter(self.entry.get()))

class Rename():
    def __init__(self, root):
        self.root = root
        self.root.geometry("300x100+200+200")
        self.root.title("Insert new file name")
        self.label_file_name = tk.Label(self.root, text="Enter a name")
        self.label_file_name.pack()
        self.entry_var = tk.StringVar()
        self.entry = tk.Entry(self.root, textvariable=self.entry_var)
        self.entry.pack()
        self.entry.focus()
        self.entry_var.set(app.filename.split("\\")[1])
        self.entry.bind("<Return>", lambda x: app.rename(self.entry.get()))

class Help():
    def __init__(self, root):
        self.root = root
        self.root.title("Shortcuts")
        self.label_file_name = tk.Label(self.root, text="Shortcuts")
        self.label_file_name.pack()
        istruzioni = """* H2
^ H3
§ <img src=...
=> red
<F2> rename"""
        self.text = tk.Text(self.root, width=30, height=6)
        self.text.insert("1.0", istruzioni)
        self.text.pack(fill=tk.BOTH, expand=1)

if __name__ == "__main__":
    # =============================== checks if folders exists &
                                   #= creates them if not
    if "text" in os.listdir():
        pass
    else:
        os.mkdir("text")

    if "img" in os.listdir():
        pass
    else:
        os.mkdir("img")

    root = tk.Tk()
    app = Ebook(root)
    app.root.title("pyem_1_5")
    root.mainloop()

Update 1.6 – highlight code

I added a way to highlight the code (for Python) when you write the code like this

>>> print(“Hello”)

    def highlight(self, code):
        "pass a string and it will be highlighted"
        # keywords to be colored in orange
        kw = kwlist
        for k in kw:
            k = k + " "
            code = code.replace(k, "<b style='color:orange'>" + k + "</b>")
        code = code.replace("\n","<br>")
        #print(code)
        # The 'indentation'
        code = code.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;")
        # functions to be clored in blue
        _def= re.findall("\w+\(", code)
        for w in _def:
            code = code.replace(w, "<b style='color:blue'>" + w[:-1] + "</b>(")
        return code

In the html_converter I added this line (we need to import re and kwlist from keyword):

import re
from keyword import kwlist
                if line[0] == ">":
                    line = self.highlight(line) + "<br>"
                    html += line

The whole code

# pyem_1_4c2 - 25/09/2019 @ Giovanni Gatto
# pyem_1_4c3_user_edition_26_set_2019_compiti
# aggiunto ctrl+p per visualizza la singola pagina html generata
# (si poteva fare col pulsante save page)
# pyem2 - correct bug about renaming files
# pyem2b - added at 196 and commented 195 (because of can't find filename) 
            # self.filename = self.lstb.get(index)
# version 1.5 - added menubar
# version 1.6 - added highlight function to higlight code
# if a line starts with ">"... so if there is >>> ...
import tkinter as tk
import glob
from time import sleep
import os
import re
from keyword import kwlist
"""
1.2
Added ctrl+s <Control+s> to bind of text
Added label to editor
1.3
added red symbol for rendering html
1.4
Added way to save render single txt file
"""

class Ebook:
    def __init__(self, root):
        """Define window for the app"""
        self.root = root
        self.root.geometry("850x400")
        self.root["bg"] = "coral"
        self.menu()
        self.editor()
        self.root.bind("<Control-b>", lambda x: self.save_ebook())

    # Widgets on the left ===============|
    def menu(self):
        """Listbox on the left with file names"""

        # commit to git
        # self.button_commit = tk.Button(self.frame2, text="Commit", command = self.commit)
        # self.button_commit.pack()

        self.menubar = tk.Menu(self.root)
        self.menubar.add_command(label="[ + ]", command = lambda: self.new_window(Win1))
        self.menubar.add_command(label="[ Delete ]", command= lambda: self.delete_file())
        self.menubar.add_command(label="[ Rename ]", command= lambda: self.new_window(Rename))
        self.menubar.add_command(label="[ Page ]", command = self.save_page)
        self.menubar.add_command(label="[ Ebook ]", command = self.save_ebook)
        self.menubar.add_command(label="[ SAVE ]", command = self.save)       
        self.menubar.add_command(label="[ Help ]", command= lambda: self.new_window(Help))
        self.root.config(menu=self.menubar)

        self.frame1 = tk.Frame(self.root)
        self.frame1["bg"] = "coral"
        self.frame1.pack(side='left', fill=tk.Y)
        self.lstb = tk.Listbox(self.frame1, width=30) # selectmode='multiple', exportselection=0)
        self.lstb['bg'] = "black"
        self.lstb['fg'] = 'gold'
        self.lstb.pack(fill=tk.Y, expand=1)
        self.lstb.bind("<<ListboxSelect>>", lambda x: self.show_text_in_editor())
        self.lstb.bind("<F2>", lambda x: self.new_window(Rename))
        self.files = glob.glob("text\\*.txt")

        for file in self.files:
            self.lstb.insert(tk.END, file)

    def new_window(self, _class):
        self.new = tk.Toplevel(self.root)
        _class(self.new)

    def commit(self):
        os.startfile("commit.bat")

    def help(self):
        print("Press <F2> to rename files")

    
    def rename(self, filename):
        self.lstb.delete("active")
        os.rename(self.filename, "text\\" + filename)
        self.files = glob.glob("text\\*.txt")
        self.reload_list_files(filename)
        # self.lstb.insert(self.files.index("text\\" + filename), "text\\" + filename)

    def new_chapter(self, filename):
        self.new.destroy()
        if not filename.endswith(".txt"):
            filename += ".txt"
        #os.chdir("text")
        with open("text\\" + filename, "w", encoding="utf-8") as file:
            file.write("")
        self.reload_list_files(filename)

    def reload_list_files(self, filename=""):
        #os.chdir("..")
        self.lstb.delete(0, tk.END)
        self.files = [f for f in glob.glob("text\\*txt")]
        for file in self.files:
            self.lstb.insert(tk.END, file)
        self.lstb.select_set(self.files.index("text\\" + filename))

    def reload_list_files_delete(self, filename=""):
        #os.chdir("..")
        self.lstb.delete(0, tk.END)
        self.files = [f for f in glob.glob("text\\*txt")]
        for file in self.files:
            self.lstb.insert(tk.END, file)

    def delete_file(self):
        for num in self.lstb.curselection():
            os.remove(self.files[num])
        self.reload_list_files_delete()

    def save(self):
        if self.text.get("1.0", tk.END) != "":
            with open(self.filename, "w", encoding="utf-8") as file:
                file.write(self.text.get("1.0", tk.END))
            self.label_file_name["text"] += "...saved"

    def save_ebook(self):
        html = ""
        with open("ebook.html", "w", encoding="utf-8") as htmlfile:
            for file in self.files: # this is the name of each file
                with open(file, "r", encoding="utf-8") as singlefile:
                    # ================= SYMBOL => HTML ==============
                    html += self.html_convert(singlefile.read())
            htmlfile.write(html)
        self.label_file_name["text"] += "...Opening Ebook"
        os.startfile("ebook.html")

    def save_page(self):
        """Save a single page v. 1.4 23/09/2019 at 05:40"""
        self.save()
        html = ""
        current = self.lstb.get(tk.ACTIVE)[:-4] # The file selected without .txt
        with open(f"{current}.html", "w", encoding="utf-8") as htmlfile:
            # opend the active (selected) item in the listbox
            with open(f"{current}.txt", "r", encoding="utf-8") as readfile:
                read = readfile.read() # get the text of the active file
                read = self.html_convert(read) # convert this text in html with *^=>
                htmlfile.write(read) # create the new file with the rendered text
        self.label_file_name["text"] += "...page rendered"
        os.startfile(f"{current}.html")
        # os.system("start ../index.html")

    def highlight(self, code):
        "pass a string and it will be highlighted"
        # keywords to be colored in orange
        kw = kwlist
        for k in kw:
            k = k + " "
            code = code.replace(k, "<b style='color:orange'>" + k + "</b>")
        code = code.replace("\n","<br>")
        #print(code)
        # The 'indentation'
        code = code.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;")
        # functions to be clored in blue
        _def= re.findall("\w+\(", code)
        for w in _def:
            code = code.replace(w, "<b style='color:blue'>" + w[:-1] + "</b>(")
        return code

    def html_convert(self, text_to_render):
        """Convert to my Markup language"""
        html = ""
        text_to_render = text_to_render.split("\n")

        for line in text_to_render:
            if line != "":
                if line[0] == ">":
                    line = self.highlight(line) + "<br>"
                    html += line
                elif line[0] == "*":
                    line = line.replace("*","")
                    html += f"<h2>{line}</h2>"
                elif line[0] == "^":
                    line = line.replace("^","")
                    html += f"<h3>{line}</h3>"
                elif line[0] == "§":
                    line = line.replace("§","")
                    if line.startswith("http"):
                        html += f"<img src='{line}' width='100%'><br>"
                    else:                
                        html += f"<img src='img\\{line}' width='100%'><br>"
                elif line[0] == "=" and line[1]== ">":
                    line = line.replace("=>", "")
                    html += f"<span style='color:red'>{line}</span>"
                else:
                    html += f"<p>{line}</p>"

        #html = self.highlight(html)
        return html

    def show_text_in_editor(self):
        """Shows text of selected file in the editor"""
        
        if not self.lstb.curselection() is ():
            index = self.lstb.curselection()[0]
            #self.filename = self.files[index] # instead of self.lstb.get(index)
            self.filename = self.lstb.get(index)
            with open(self.filename, "r", encoding="utf-8") as file:
                content = file.read()
            self.text.delete("1.0", tk.END)
            self.text.insert(tk.END, content)
            self.label_file_name['text'] = self.filename

    def editor(self):
        """The text where you can write"""
        self.label_file_name = tk.Label(self.root, text="Editor - choose a file on the left")
        self.label_file_name.pack()
        self.text = tk.Text(self.root, wrap=tk.WORD)
        self.text['bg'] = "darkgreen"
        self.text['fg'] = 'white'
        self.text['font'] = "Arial 24"
        self.text.pack(fill=tk.Y, expand=1)
        self.text.bind("<Control-s>", lambda x: self.save())
        self.text.bind("<Control-p>", lambda x: self.save_page())


class Win1():
    def __init__(self, root):
        self.root = root
        self.root.geometry("300x100")
        self.root.title("Insert new file name")
        self.label_file_name = tk.Label(self.root, text="Enter a name")
        self.label_file_name.pack()
        self.entry = tk.Entry(self.root)
        self.entry.pack()
        self.entry.focus()
        self.entry.bind("<Return>", lambda x: app.new_chapter(self.entry.get()))

class Rename():
    def __init__(self, root):
        self.root = root
        self.root.geometry("300x100+200+200")
        self.root.title("Insert new file name")
        self.label_file_name = tk.Label(self.root, text="Enter a name")
        self.label_file_name.pack()
        self.entry_var = tk.StringVar()
        self.entry = tk.Entry(self.root, textvariable=self.entry_var)
        self.entry.pack()
        self.entry.focus()
        self.entry_var.set(app.filename.split("\\")[1])
        self.entry.bind("<Return>", lambda x: app.rename(self.entry.get()))

class Help():
    def __init__(self, root):
        self.root = root
        self.root.title("Shortcuts")
        self.label_file_name = tk.Label(self.root, text="Shortcuts")
        self.label_file_name.pack()
        istruzioni = """* H2
^ H3
§ <img src=...
=> red
<F2> rename
> To highlight code"""
        self.text = tk.Text(self.root, width=30, height=6)
        self.text.insert("1.0", istruzioni)
        self.text.pack(fill=tk.BOTH, expand=1)

if __name__ == "__main__":
    # =============================== checks if folders exists &
                                   #= creates them if not
    if "text" in os.listdir():
        pass
    else:
        os.mkdir("text")

    if "img" in os.listdir():
        pass
    else:
        os.mkdir("img")

    root = tk.Tk()
    app = Ebook(root)
    app.root.title("pyem_1_6")
    root.mainloop()

 

What next?

I think I am going to add a voice in the menu to create pdf files from the txt files.

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.