-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain_frame.py
200 lines (167 loc) · 8.39 KB
/
main_frame.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
from os.path import basename # Get filename from entire path
import wx
import engine
def tb_add_tool(tb, id, name, img, description):
""" Helper method for adding tools to a toolbar, mainly due to the need to use WX's native icons. """
tb.AddTool(id, name, wx.ArtProvider.GetBitmap(img), description)
class MainFrame(wx.Frame):
""" The application's main window """
def __init__(self, config, prefs, parent = None, doc = None, *args, **kwargs):
# Initialise the super (wx.Frame) class
super().__init__(parent, title="Untitled - Libraille", size=(800, 600))
self.config = config
self.prefs = prefs
self._doc: engine.Document = None # The loaded Document from the engine
self._file_name: str = None # Name of the *braille* file we're editting
self.modified: bool = False
self.CreateStatusBar()
# Create and attach the MenuBar and ToolBar
self.menu_bar = self.create_menu_bar()
self.SetMenuBar(self.menu_bar)
self.tool_bar = self.create_tool_bar()
self.SetToolBar(self.tool_bar)
self.text = wx.TextCtrl(self, style=wx.TE_MULTILINE) # The main edit area
self.register_events()
self.Show(True)
def create_menu_bar(self):
""" Create and return the application's menu bar. """
file = wx.Menu()
file.Append(wx.ID_NEW, "&New\tCtrl-n", "Create a new braille document")
file.Append(wx.ID_OPEN, "&Import\tCtrl-o", "Import and convert a print document")
file.AppendSeparator()
file.Append(wx.ID_SAVE, "&Save\tCtrl-s", "Save the current braille document")
file.Append(wx.ID_SAVEAS, "Save &As\tCtrl-Shift-s", "Save the current braille document under a new name")
file.AppendSeparator()
file.Append(wx.ID_EXIT, "E&xit\t\tCtrl-q", "Close this program")
edit = wx.Menu()
edit.Append(wx.ID_UNDO, "&Undo\tCtrl-z", "Undoes the last operation")
edit.Append(wx.ID_REDO, "&Redo\tCtrl-y", "Redoes the last operation")
edit.AppendSeparator()
edit.Append(wx.ID_CUT, "&Cut\tCtrl-x", "Move text to the clipboard")
edit.Append(wx.ID_COPY, "Cop&y\tCtrl-c", "Copies text to the clipboard")
edit.Append(wx.ID_PASTE, "&Paste\tCtrl-v", "Insert text from the clipboard")
edit.AppendSeparator()
edit.Append(wx.ID_PREFERENCES, "P&references\tCtrl-,", "Adjust transcription settings")
menu = wx.MenuBar()
menu.Append(file, "&File")
menu.Append(edit, "&Edit")
return menu
def create_tool_bar(self):
""" Create and return the application's toolbar. """
tb = self.CreateToolBar(wx.TB_DEFAULT_STYLE, wx.ID_ANY, "Main")
tb_add_tool(tb, wx.ID_NEW, "New", wx.ART_NEW, "Create a new braille document")
tb_add_tool(tb, wx.ID_OPEN, "Import", wx.ART_FILE_OPEN, "Import and convert a print document")
tb.AddSeparator()
tb_add_tool(tb, wx.ID_SAVE, "Save", wx.ART_FILE_SAVE, "Save the current braille document")
tb_add_tool(tb, wx.ID_SAVEAS, "Save As", wx.ART_FILE_SAVE_AS, "Save the current braille document under a new name")
tb.AddSeparator()
tb_add_tool(tb, wx.ID_UNDO, "Undo", wx.ART_UNDO, "Undo the last operation")
tb_add_tool(tb, wx.ID_REDO, "Redo", wx.ART_REDO, "Redo the last operation")
tb.AddSeparator()
tb_add_tool(tb, wx.ID_CUT, "Cut", wx.ART_CUT, "Move text to the clipboard")
tb_add_tool(tb, wx.ID_COPY, "Copy", wx.ART_COPY, "Copy text to the clipboard")
tb_add_tool(tb, wx.ID_PASTE, "Copy", wx.ART_PASTE, "Insert text from the clipboard")
tb.Realize() # Allow WX to position and size all widgets on the toolbar
return tb
def register_events(self):
self.Bind(wx.EVT_CLOSE, self.on_close)
self.Bind(wx.EVT_MENU, self.on_exit, None, wx.ID_EXIT)
self.Bind(wx.EVT_MENU, self.on_open, None, wx.ID_OPEN)
self.Bind(wx.EVT_MENU, self.on_save, None, wx.ID_SAVE)
self.Bind(wx.EVT_MENU, self.on_save_as, None, wx.ID_SAVEAS)
self.Bind(wx.EVT_TEXT, self.on_text_change, self.text)
self.Bind(wx.EVT_MENU, self.on_undo, None, wx.ID_UNDO)
self.Bind(wx.EVT_MENU, self.on_redo, None, wx.ID_REDO)
self.Bind(wx.EVT_MENU, self.on_cut, None, wx.ID_CUT)
self.Bind(wx.EVT_MENU, self.on_copy, None, wx.ID_COPY)
self.Bind(wx.EVT_MENU, self.on_paste, None, wx.ID_PASTE)
self.Bind(wx.EVT_MENU, self.on_preferences, None, wx.ID_PREFERENCES)
## EVENT HANDLERS ##
def on_open(self, evt):
# Create and show an open file dialog so the user can select a file
# FIX ME: Add filters so only supported file types are allowed.
open_dlg = wx.FileDialog(self, "Select a file to convert", style=wx.FD_OPEN)
if open_dlg.ShowModal() == wx.ID_OK:
self.SetRepresentedFilename(open_dlg.GetFilename())
self.file_name = None # This is the name of the braille file, which hasn't been saved yet
# Open, parse and convert the print file with the engine.
self._doc = engine.Document(
open_dlg.GetPath(), # Path of the user-specified file
self.config.ReadInt("engine/wrap-width", 40) # 40 is default if wrap-width is not set
)
self.text.SetValue(str(self._doc))
evt.Skip() # Tell WX this event has been fully handled
def get_save_path(self):
""" Ask the user to save and return the path. """
save_dlg = wx.FileDialog(self, "Save braille document", style=wx.FD_SAVE, wildcard="BRF File (*.brf)|*.brf|BRL File (*.brl)|*.brl")
if save_dlg.ShowModal() == wx.ID_OK:
return save_dlg.GetPath()
else:
return None # Cancelled
def on_save(self, evt):
if self.file_name is None:
self.file_name = self.get_save_path()
if self.file_name is not None:
# Write the file's contents to disk
with open(self.file_name, "w") as f:
f.write(self.text.GetValue())
self.modified = False # Just saved, so copy on disk matches copy in memory
def on_save_as(self, evt):
file_name = self.get_save_path()
if file_name is not None:
self.file_name = file_name
with open(self.file_name, "w") as f:
f.write(self.text.GetValue())
self.modified = False
def on_close(self, evt):
# If we're allowed to prevent exiting and the document has been modified
if evt.CanVeto() and self.modified:
# If the document was previously saved, this is the file name, otherwise it defaults to "Untitled"
fname = basename(self.file_name) if self.file_name is not None else "Untitled"
# Ask the user if they'd like to save
result = wx.MessageBox(f"Want to save your changes to \"{fname}\"?", "Save changes?", wx.CANCEL | wx.NO | wx.YES, self)
if result == wx.CANCEL:
evt.Veto() # Don't exit
return
elif result == wx.YES:
self.on_save_as(None)
evt.Skip()
def on_text_change(self, evt):
self.modified = True
def on_exit(self, evt):
# We need to use wx.CallAfter() here because otherwise the event loop is prematurely terminated
wx.CallAfter(self.Close)
def on_undo(self, evt):
self.text.Undo()
evt.Skip()
def on_redo(self, evt):
self.text.Redo()
evt.Skip()
def on_cut(self, evt):
self.text.Cut()
evt.Skip()
def on_copy(self, evt):
self.text.Copy()
evt.Skip()
def on_paste(self, evt):
self.text.Paste()
evt.Skip()
def on_preferences(self, evt):
""" Show the preferences dialog.
This blocks on Windows systems, but is asynchronous on macOS and Linux, so the main UI continues to function. """
# Passing `self` sets the main window as the parent window
self.prefs.Show(self)
evt.Skip()
## PROPERTIES ##
@property
def file_name(self):
""" The name of the converted *braille* file being editted. """
return self._file_name
@file_name.setter
def file_name(self, val):
self._file_name = val
# Update the window title
if val is not None:
self.SetTitle(basename(val)[:val.rfind(".")] + " - Libraille")
else:
self.SetTitle("Unsaved - Libraille")