-
Notifications
You must be signed in to change notification settings - Fork 13
/
qt_driver.py
2174 lines (1910 loc) · 89.9 KB
/
qt_driver.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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
###########################################################################
#
# Copyright 2015-2018 Robert B. Lowrie (http://github.com/lowrie)
#
# This file is part of pyRouterJig.
#
# pyRouterJig is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# pyRouterJig is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# pyRouterJig; see the file LICENSE. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
'''
Contains the main driver, using pySide or pyQt.
'''
from __future__ import print_function
import os
import sys
import traceback
import webbrowser
import copy
import shutil
from io import BytesIO
from decimal import getcontext
from future.utils import lrange
from PIL import Image
from PIL import PngImagePlugin
from PyQt5 import QtCore, QtGui, QtWidgets
import qt_fig
import qt_config
import qt_utils
import config_file
import router
import spacing
import utils
import doc
import serialize
import threeDS
class Driver(QtWidgets.QMainWindow):
'''
Qt driver for pyRouterJig
'''
def __init__(self, parent=None, app=None):
QtWidgets.QMainWindow.__init__(self, parent)
sys.excepthook = self.exception_hook
self.except_handled = False
# translator initialized in load config but we need the object created first
self.transl = QtCore.QTranslator()
# Read the config file. We wait until the end of this init to print
# the status message, because we need the statusbar to be created first.
(self.config, msg) = self.load_config(app)
# Form the units
self.units = utils.Units(self.config.english_separator, self.config.metric,
self.config.num_increments, self.transl)
self.doc = doc.Doc(self.units)
# Create an initial joint. Even though another joint may be opened
# later, we do this now so that the initial widget layout may be
# created.
bit_width = self.units.abstract_to_increments(self.config.bit_width)
bit_depth = self.units.abstract_to_increments(self.config.bit_depth)
bit_angle = self.units.abstract_to_float(self.config.bit_angle)
bit_gentle = self.config.bit_gentle
self.bit = router.Router_Bit(self.units, bit_width, bit_depth, bit_angle, bit_gentle)
self.boards = []
board_width = self.units.abstract_to_increments(self.config.board_width)
for _ in lrange(4):
self.boards.append(router.Board(self.bit, width=board_width))
self.boards[2].set_active(False)
self.boards[3].set_active(False)
dbt = self.units.abstract_to_increments(self.config.double_board_thickness)
self.boards[2].set_height(self.bit, dbt)
self.boards[3].set_height(self.bit, dbt)
self.template = router.Incra_Template(self.units, self.boards)
self.equal_spacing = spacing.Equally_Spaced(self.bit, self.boards, self.config)
self.equal_spacing.set_cuts()
self.var_spacing = spacing.Variable_Spaced(self.bit, self.boards, self.config)
self.var_spacing.set_cuts()
self.edit_spacing = spacing.Edit_Spaced(self.bit, self.boards, self.config)
self.edit_spacing.set_cuts(self.equal_spacing.cuts)
self.spacing = self.equal_spacing # the default
self.spacing_index = None # to be set in layout_widgets()
self.description = None
self.woods = {}
# Create the main frame and menus
self.create_status_bar()
self.create_widgets()
self.create_menu()
# Draw the initial figure
self.draw()
# Keep track whether the current figure has been saved. We initialize to true,
# because we assume that that the user does not want the default joint saved.
self.file_saved = True
# The working_dir is where we save files. We start with the user home
# directory. Ideally, if using the script to start the program, then
# we'd use the cwd, but that's complicated.
self.working_dir = os.path.expanduser('~')
# Indices for screenshot/save and table filenames
self.screenshot_index = None
self.table_index = None
# Initialize keyboard modifiers
self.control_key = False
self.alt_key = False
# Initialize the configuration window, even though we might not use
# it. We do this so that if certain preferences are changed via the
# menus, such as show_caul, the config window keeps track whether any such
# changes have occurred, in order to enable its Save button.
self.config_window = qt_config.Config_Window(self.config, self.units, self)
# ... show the status message from reading the configuration file
self.status_message(msg)
def load_config(self, app=None):
'''
Sets the config attribute, by either
1) Reading an existing config file
2) Updating an existing config file and loading it
3) Creating the config file, if it does not exist
'''
c = config_file.Configuration()
r = c.read_config()
locale = QtCore.QLocale()
if r != 1 and getattr(c.config, "language", None) != None:
locale = QtCore.QLocale(c.config.language)
res = self.transl.load("pyRouterJig_%s.qm" % locale.name(), ".\\ts")
if res and app != None:
app.installTranslator(self.transl)
if r > 0:
tools = 'Tools'
if utils.isMac():
tools = 'pyRouterJig'
if r == 1:
# The config file does not exist. Ask the user whether they want metric or english
# units
box = QtWidgets.QMessageBox(self)
box.setTextFormat(QtCore.Qt.RichText)
box.setIcon(QtWidgets.QMessageBox.NoIcon)
box.setText(self.transl.tr(
'<font size=5 color=red>Welcome to <i>pyRouterJig</i> !</font>'))
question = self.transl.tr('<font size=5>Please select a unit system below.'\
' The configuration file<p><tt>{}</tt><p>'\
' will be created to store this setting,'\
' along with additional default settings. These options'\
' may be changed later by selecting <b>Preferences</b> under'\
' the <b>{}</b> menu.</font>').format(c.filename, tools)
box.setInformativeText(question)
buttonMetric = box.addButton(self.transl.tr('Metric (millimeters)'),
QtWidgets.QMessageBox.AcceptRole)
buttonEnglish = box.addButton(self.transl.tr('English (inches)'),
QtWidgets.QMessageBox.AcceptRole)
box.setDefaultButton(buttonEnglish)
box.raise_()
box.exec_()
clicked = box.clickedButton()
metric = (clicked == buttonMetric)
c.create_config(metric)
else: # r == 2
# The config file exists, but it's out of date, so
# update it. Tell the user and use the old metric setting.
backup = c.filename + c.config.version
shutil.move(c.filename, backup)
metric = c.config.metric
rc = c.create_config(metric)
box = QtWidgets.QMessageBox(self)
box.setTextFormat(QtCore.Qt.RichText)
box.setIcon(QtWidgets.QMessageBox.Warning)
box.setText(self.transl.tr(
'<font size=5 color=red>Welcome to <i>pyRouterJig</i> !'))
warning = self.transl.tr('<font size=5>A new configuration file<p><tt>{}</tt><p>'\
'has been created. The old version was saved'\
' to<p><tt>{}</tt><p> ').format(c.filename, backup)
if rc == 0:
warning += self.transl.tr('The previous setting of'\
'<p><i>metric = {}</i><p>has been migrated.'\
' But any other changes that you may have made'\
' to the old file will need to be migrated to the'\
' new file, or by selecting <b>Preferences</b>'\
' under the <b>{}</b> menu.').format(metric, tools)
else:
warning += self.transl.tr('The old configuration values were migrated'\
' and any new values were set to their default.')
box.setInformativeText(warning)
box.raise_()
box.exec_()
self.raise_()
msg = 'Configuration file %s created' % c.filename
c.read_config()
else:
# The config file exists and is current
msg = self.transl.tr('Read configuration file %s') % c.filename
return (c.config, msg)
def center(self):
'''Centers the app in the screen'''
frameGm = self.frameGeometry()
screen = QtWidgets.QApplication.desktop().screenNumber(
QtWidgets.QApplication.desktop().cursor().pos())
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
frameGm.moveCenter(centerPoint)
self.move(frameGm.topLeft())
def exception_hook(self, etype, value, trace):
'''
Handler for all exceptions.
'''
if self.except_handled:
return
self.except_handled = True
if self.config.debug:
tmp = traceback.format_exception(etype, value, trace)
traceback.print_tb(trace)
else:
tmp = traceback.format_exception_only(etype, value)
exception = '\n'.join(tmp)
QtWidgets.QMessageBox.warning(self, 'Error', exception)
self.except_handled = False
def create_menu(self):
'''
Creates the drop-down menus.
'''
self.menubar = self.menuBar()
# always attach the menubar to the application window, even on the Mac
# self.menubar.setNativeMenuBar(False)
# Add the file menu
file_menu = self.menubar.addMenu(self.transl.tr('File'))
open_action = QtWidgets.QAction(self.transl.tr('&Open File...'), self)
open_action.setShortcut('Ctrl+O')
open_action.setStatusTip(self.transl.tr('Opens a previously saved image of joint'))
open_action.triggered.connect(self._on_open)
file_menu.addAction(open_action)
save_action = QtWidgets.QAction(self.transl.tr('&Save File...'), self)
save_action.setShortcut('Ctrl+S')
save_action.setStatusTip(self.transl.tr('Saves an image of the joint to a file'))
save_action.triggered.connect(self._on_save)
file_menu.addAction(save_action)
file_menu.addSeparator()
print_action = QtWidgets.QAction(self.transl.tr('&Print...'), self)
print_action.setShortcut('Ctrl+P')
print_action.setStatusTip(self.transl.tr('Print the figure'))
print_action.triggered.connect(self._on_print)
file_menu.addAction(print_action)
file_menu.addSeparator()
exit_action = QtWidgets.QAction(self.transl.tr('&Quit pyRouterJig'), self)
exit_action.setShortcut('Ctrl+Q')
exit_action.setStatusTip(self.transl.tr('Quit pyRouterJig'))
exit_action.triggered.connect(self._on_exit)
file_menu.addSeparator()
file_menu.addAction(exit_action)
# comment out for now...
# table_action = QtWidgets.QAction('Print Table...', self)
# table_action.setStatusTip('Print a table of router pass locations')
# table_action.triggered.connect(self._on_print_table)
# file_menu.addAction(table_action)
# Add view menu
view_menu = self.menubar.addMenu(self.transl.tr('View'))
self.caul_action = QtWidgets.QAction(self.transl.tr('Caul Template'), self, checkable=True)
self.caul_action.setStatusTip(self.transl.tr('Toggle caul template'))
self.caul_action.triggered.connect(self._on_caul)
view_menu.addAction(self.caul_action)
self.caul_action.setChecked(self.config.show_caul)
self.finger_size_action = QtWidgets.QAction(self.transl.tr('Finger Widths'),
self, checkable=True)
self.finger_size_action.setStatusTip(self.transl.tr('Toggle viewing finger sizes'))
self.finger_size_action.triggered.connect(self._on_finger_sizes)
view_menu.addAction(self.finger_size_action)
self.finger_size_action.setChecked(self.config.show_finger_widths)
self.fit_action = QtWidgets.QAction(self.transl.tr('Fit'), self, checkable=True)
self.fit_action.setStatusTip(self.transl.tr('Toggle showing fit of joint'))
self.fit_action.triggered.connect(self._on_fit)
view_menu.addAction(self.fit_action)
self.fit_action.setChecked(self.config.show_fit)
self.zoom_action = QtWidgets.QAction(self.transl.tr('Zoom Mode'), self, checkable=True)
self.zoom_action.setStatusTip(self.transl.tr('Toggle zoom mode'))
self.zoom_action.triggered.connect(self._on_zoom)
view_menu.addAction(self.zoom_action)
self.fig.enable_zoom_mode(False)
self.fit_action.setChecked(self.fig.zoom_mode)
view_menu.addSeparator()
pass_menu = view_menu.addMenu(self.transl.tr('Router Passes'))
self.pass_id_action = QtWidgets.QAction(self.transl.tr('Identifiers'), self, checkable=True)
self.pass_id_action.setStatusTip(self.transl.tr('Toggle viewing router pass identifiers'))
self.pass_id_action.triggered.connect(self._on_pass_id)
pass_menu.addAction(self.pass_id_action)
self.pass_id_action.setChecked(self.config.show_router_pass_identifiers)
self.pass_location_action = QtWidgets.QAction(self.transl.tr('Locations'),
self, checkable=True)
self.pass_location_action.setStatusTip(self.transl.tr(
'Toggle viewing router pass locations'))
self.pass_location_action.triggered.connect(self._on_pass_location)
pass_menu.addAction(self.pass_location_action)
self.pass_location_action.setChecked(self.config.show_router_pass_locations)
# The Mac automatically adds full screen to the View menu, but do so for other platforms
# if not utils.isMac():
view_menu.addSeparator()
fullscreen_action = QtWidgets.QAction(self.transl.tr('Full Screen Mode'),
self, checkable=True)
fullscreen_action.setShortcut('Ctrl+F')
fullscreen_action.setStatusTip(self.transl.tr('Toggle full-screen mode'))
fullscreen_action.triggered.connect(self._on_fullscreen)
view_menu.addAction(fullscreen_action)
# Add Tools menu
tools_menu = self.menubar.addMenu(self.transl.tr('Tools'))
screenshot_action = QtWidgets.QAction(self.transl.tr('Screenshot...'), self)
screenshot_action.setShortcut('Ctrl+W')
screenshot_action.setStatusTip(self.transl.tr(
'Saves an image of the pyRouterJig window to a file'))
screenshot_action.triggered.connect(self._on_screenshot)
tools_menu.addAction(screenshot_action)
# We need to make this action persistent, so that we can
# enable and disable it (until all of its functionality is
# written)
self.threeDS_action = QtWidgets.QAction(self.transl.tr('&Export 3DS...'), self)
self.threeDS_action.setShortcut('Ctrl+E')
self.threeDS_action.setStatusTip(self.transl.tr('Export the joint to a 3DS file'))
self.threeDS_action.triggered.connect(self._on_3ds)
tools_menu.addAction(self.threeDS_action)
self.threeDS_enabler()
tools_menu.addSeparator()
pref_action = QtWidgets.QAction(self.transl.tr('Preferences...'), self)
pref_action.setShortcut('Ctrl+,')
pref_action.setStatusTip(self.transl.tr('Open preferences'))
pref_action.triggered.connect(self._on_preferences)
tools_menu.addAction(pref_action)
# Add the help menu
help_menu = self.menubar.addMenu(self.transl.tr('Help'))
about_action = QtWidgets.QAction(self.transl.tr('&About pyRouterJig'), self)
about_action.setShortcut('Ctrl+A')
about_action.setStatusTip(self.transl.tr('About this program'))
about_action.triggered.connect(self._on_about)
help_menu.addAction(about_action)
view_menu.addSeparator()
doclink_action = QtWidgets.QAction(self.transl.tr('&Documentation...'), self)
doclink_action.setStatusTip(self.transl.tr('Opens documentation page in web browser'))
doclink_action.triggered.connect(self._on_doclink)
help_menu.addAction(doclink_action)
def create_wood_combo_box(self, woods, patterns, has_none=False):
'''
Creates a wood selection combox box
'''
cb = qt_utils.PreviewComboBox(self)
# Set the default wood.
if has_none:
# If adding NONE, make that the default
defwood = 'NONE'
else:
defwood = QtCore.Qt.DiagCrossPattern
if self.config.default_wood in self.woods.values():
defwood = self.config.default_wood
self.populate_wood_combo_box(cb, woods, patterns, defwood, has_none)
# Don't let the user change the text for each selection
cb.setEditable(False)
return cb
def populate_wood_combo_box(self, cb, woods, patterns, defwood, has_none):
'''
Fills the wood combo box
'''
cb.blockSignals(True)
cb.clear()
if has_none:
cb.addItem('NONE')
# Add the woods in the wood_images directory
skeys = sorted(woods.keys())
#combo boxes now store values as well as keys
for k in skeys:
cb.addItem(k, woods.get(k))
# Next add patterns
if skeys:
cb.insertSeparator(len(skeys))
skeys = sorted(patterns.keys())
for k in skeys:
cb.addItem(k, patterns.get(k))
# Set the index to the default wood
i = max(0, cb.findData(defwood))
cb.setCurrentIndex(i)
cb.blockSignals(False)
def create_widgets(self):
'''
Creates all of the widgets in the main panel
'''
self.main_frame = QtWidgets.QWidget()
lineEditWidth = 80
us = self.units.units_string(withParens=True)
# Create the figure canvas, using mpl interface
self.fig = qt_fig.Qt_Fig(self.template, self.boards, self.config)
self.fig.canvas.setParent(self.main_frame)
self.fig.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
self.fig.canvas.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
self.fig.canvas.setFocus()
# Board width line edit
self.le_board_width_label = QtWidgets.QLabel(self.transl.tr('Board Width{}').format(us))
self.le_board_width = QtWidgets.QLineEdit(self.main_frame)
self.le_board_width.setFixedWidth(lineEditWidth)
self.le_board_width.setText(self.units.increments_to_string(self.boards[0].width))
self.le_board_width.editingFinished.connect(self._on_board_width)
self.le_board_width.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
# Bit width line edit
self.le_bit_width_label = QtWidgets.QLabel(self.transl.tr('Bit Width{}').format(us))
self.le_bit_width = QtWidgets.QLineEdit(self.main_frame)
self.le_bit_width.setFixedWidth(lineEditWidth)
self.le_bit_width.setText(self.units.increments_to_string(self.bit.width))
self.le_bit_width.editingFinished.connect(self._on_bit_width)
# Bit depth line edit
self.le_bit_depth_label = QtWidgets.QLabel(self.transl.tr('Bit Depth{}').format(us))
self.le_bit_depth = QtWidgets.QLineEdit(self.main_frame)
self.le_bit_depth.setFixedWidth(lineEditWidth)
self.le_bit_depth.setText(self.units.increments_to_string(self.bit.depth))
self.le_bit_depth.editingFinished.connect(self._on_bit_depth)
# Bit angle line edit
self.le_bit_angle_label = QtWidgets.QLabel(self.transl.tr('Bit Angle (deg.)'))
self.le_bit_angle = QtWidgets.QLineEdit(self.main_frame)
self.le_bit_angle.setFixedWidth(lineEditWidth)
self.le_bit_angle.setText('%g' % self.bit.angle)
self.le_bit_angle.editingFinished.connect(self._on_bit_angle)
# Double and double-double board thicknesses
self.le_boardm_label = []
self.le_boardm = []
for i in lrange(2):
self.le_boardm_label.append(QtWidgets.QLabel(self.transl.tr('Thickness{}').format(us)))
self.le_boardm.append(QtWidgets.QLineEdit(self.main_frame))
self.le_boardm[i].setFixedWidth(lineEditWidth)
s = self.units.increments_to_string(self.boards[i+2].dheight)
self.le_boardm[i].setText(s)
self.le_boardm[0].editingFinished.connect(self._on_boardm0)
self.le_boardm[1].editingFinished.connect(self._on_boardm1)
# Wood combo boxes
(woods, patterns) = qt_utils.create_wood_dict(self.config.wood_images, self.transl)
# ... combine the wood images and patterns
self.woods = copy.deepcopy(woods)
self.woods.update(patterns)
# ... create the combo boxes and their labels
self.cb_wood = []
self.cb_wood.append(self.create_wood_combo_box(woods, patterns))
self.cb_wood.append(self.create_wood_combo_box(woods, patterns))
self.cb_wood.append(self.create_wood_combo_box(woods, patterns, True))
self.cb_wood.append(self.create_wood_combo_box(woods, patterns, True))
self.cb_wood_label = []
self.cb_wood_label.append(QtWidgets.QLabel(self.transl.tr('Top Board')))
self.cb_wood_label.append(QtWidgets.QLabel(self.transl.tr('Bottom Board')))
self.cb_wood_label.append(QtWidgets.QLabel(self.transl.tr('Double Board')))
self.cb_wood_label.append(QtWidgets.QLabel(self.transl.tr('Double-Double Board')))
# Disable double* boards, for now
self.le_boardm[0].setEnabled(False)
self.le_boardm[1].setEnabled(False)
self.le_boardm[0].setStyleSheet("color: gray;")
self.le_boardm[1].setStyleSheet("color: gray;")
self.le_boardm_label[0].setStyleSheet("color: gray;")
self.le_boardm_label[1].setStyleSheet("color: gray;")
self.cb_wood[3].setEnabled(False)
self.cb_wood_label[3].setStyleSheet("color: gray;")
# Equal spacing widgets
params = self.equal_spacing.params
labels = self.equal_spacing.labels
# ...first slider
p = params['Spacing']
self.es_slider0_label = QtWidgets.QLabel(labels[0])
self.es_slider0 = QtWidgets.QSlider(QtCore.Qt.Horizontal, self.main_frame)
self.es_slider0.setFocusPolicy(QtCore.Qt.StrongFocus)
self.es_slider0.setMinimum(p.vMin)
self.es_slider0.setMaximum(p.vMax)
self.es_slider0.setValue(p.v)
self.es_slider0.setTickPosition(QtWidgets.QSlider.TicksBelow)
utils.set_slider_tick_interval(self.es_slider0)
self.es_slider0.valueChanged.connect(self._on_es_slider0)
self.es_slider0.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# ...second slider
p = params['Width']
self.es_slider1_label = QtWidgets.QLabel(labels[1])
self.es_slider1 = QtWidgets.QSlider(QtCore.Qt.Horizontal, self.main_frame)
self.es_slider1.setFocusPolicy(QtCore.Qt.StrongFocus)
self.es_slider1.setMinimum(p.vMin)
self.es_slider1.setMaximum(p.vMax)
self.es_slider1.setValue(p.v)
self.es_slider1.setTickPosition(QtWidgets.QSlider.TicksBelow)
utils.set_slider_tick_interval(self.es_slider1)
self.es_slider1.valueChanged.connect(self._on_es_slider1)
self.es_slider1.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# ...check box for centering
p = params['Centered']
self.cb_es_centered = QtWidgets.QCheckBox(labels[2], self.main_frame)
self.cb_es_centered.setChecked(True)
self.cb_es_centered.stateChanged.connect(self._on_cb_es_centered)
# Variable spacing widgets
params = self.var_spacing.params
labels = self.var_spacing.labels
# ...combox box for fingers
p = params['Fingers']
self.cb_vsfingers_label = QtWidgets.QLabel(labels[0]) # labels[0]
self.cb_vsfingers = qt_utils.PreviewComboBox(self.main_frame)
self.cb_vsfingers.setFocusPolicy(QtCore.Qt.StrongFocus)
self.update_cb_vsfingers(p.vMin, p.vMax, p.v)
p = params['Spacing']
self.vs_slider0_label = QtWidgets.QLabel(labels[1], self.main_frame) # labels[1]
self.vs_slider0 = QtWidgets.QSlider(QtCore.Qt.Horizontal, self.main_frame)
self.vs_slider0.setFocusPolicy(QtCore.Qt.StrongFocus)
self.vs_slider0.setMinimum(p.vMin)
self.vs_slider0.setMaximum(p.vMax)
self.vs_slider0.setValue(p.v)
self.vs_slider0.setTickPosition(QtWidgets.QSlider.TicksBelow)
self.vs_slider0.setSingleStep(1)
utils.set_slider_tick_interval(self.vs_slider0)
self.vs_slider0.valueChanged.connect(self._on_vs_slider0)
self.vs_slider0.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# line out lables (haveno idea why
width = (self.vs_slider0_label.width())
self.cb_vsfingers_label.setFixedWidth(width // 2)
height = (self.vs_slider0_label.height())
self.vs_slider0_label.setFixedHeight((height * 10) // 8)
self.cb_vsfingers_label.setFixedHeight((height * 8) // 10)
# self.vs_slider0.setFixedHeight(self.cb_vsfingers.height())
# ...check box for centering
p = params['Inverted']
self.cb_vs_inverted = QtWidgets.QCheckBox(labels[2], self.main_frame) # labels[2]
self.cb_vs_inverted.setChecked(p.v)
self.cb_vs_inverted.stateChanged.connect(self._cb_vs_inverted)
# Edit spacing widgets
edit_btn_undo = QtWidgets.QPushButton(self.transl.tr('Undo'), self.main_frame)
edit_btn_undo.clicked.connect(self._on_edit_undo)
edit_btn_undo.setToolTip(self.transl.tr('Undo the last change'))
edit_btn_add = QtWidgets.QPushButton(self.transl.tr('Add'), self.main_frame)
edit_btn_add.clicked.connect(self._on_edit_add)
edit_btn_add.setToolTip(self.transl.tr('Add a cut (if there is space to add cuts)'))
edit_btn_del = QtWidgets.QPushButton(self.transl.tr('Delete'), self.main_frame)
edit_btn_del.clicked.connect(self._on_edit_del)
edit_btn_del.setToolTip(self.transl.tr('Delete the active cuts'))
edit_move_label = QtWidgets.QLabel(self.transl.tr('Move'))
edit_move_label.setToolTip(self.transl.tr('Moves the active cuts'))
edit_btn_moveL = QtWidgets.QToolButton(self.main_frame)
edit_btn_moveL.setArrowType(QtCore.Qt.LeftArrow)
edit_btn_moveL.clicked.connect(self._on_edit_moveL)
edit_btn_moveL.setToolTip(self.transl.tr('Move active cuts to left 1 increment'))
edit_btn_moveR = QtWidgets.QToolButton(self.main_frame)
edit_btn_moveR.setArrowType(QtCore.Qt.RightArrow)
edit_btn_moveR.clicked.connect(self._on_edit_moveR)
edit_btn_moveR.setToolTip(self.transl.tr('Move active cuts to right 1 increment'))
edit_widen_label = QtWidgets.QLabel(self.transl.tr('Widen'))
edit_widen_label.setToolTip(self.transl.tr('Widens the active cuts'))
edit_btn_widenL = QtWidgets.QToolButton(self.main_frame)
edit_btn_widenL.setArrowType(QtCore.Qt.LeftArrow)
edit_btn_widenL.clicked.connect(self._on_edit_widenL)
edit_btn_widenL.setToolTip(self.transl.tr('Widen active cuts 1 increment on left side'))
edit_btn_widenR = QtWidgets.QToolButton(self.main_frame)
edit_btn_widenR.setArrowType(QtCore.Qt.RightArrow)
edit_btn_widenR.clicked.connect(self._on_edit_widenR)
edit_btn_widenR.setToolTip(self.transl.tr('Widen active cuts 1 increment on right side'))
edit_trim_label = QtWidgets.QLabel(self.transl.tr('Trim'))
edit_trim_label.setToolTip(self.transl.tr('Trims the active cuts'))
edit_btn_trimL = QtWidgets.QToolButton(self.main_frame)
edit_btn_trimL.setArrowType(QtCore.Qt.LeftArrow)
edit_btn_trimL.clicked.connect(self._on_edit_trimL)
edit_btn_trimL.setToolTip(self.transl.tr('Trim active cuts 1 increment on left side'))
edit_btn_trimR = QtWidgets.QToolButton(self.main_frame)
edit_btn_trimR.setArrowType(QtCore.Qt.RightArrow)
edit_btn_trimR.clicked.connect(self._on_edit_trimR)
edit_btn_trimR.setToolTip(self.transl.tr('Trim active cuts 1 increment on right side'))
edit_btn_toggle = QtWidgets.QPushButton(self.transl.tr('Toggle'), self.main_frame)
edit_btn_toggle.clicked.connect(self._on_edit_toggle)
edit_btn_toggle.setToolTip(self.transl.tr(
'Toggles the cut at cursor between active and deactive'))
edit_btn_cursorL = QtWidgets.QToolButton(self.main_frame)
edit_btn_cursorL.setArrowType(QtCore.Qt.LeftArrow)
edit_btn_cursorL.clicked.connect(self._on_edit_cursorL)
edit_btn_cursorL.setToolTip(self.transl.tr('Move cut cursor to left'))
edit_btn_cursorR = QtWidgets.QToolButton(self.main_frame)
edit_btn_cursorR.setArrowType(QtCore.Qt.RightArrow)
edit_btn_cursorR.clicked.connect(self._on_edit_cursorR)
edit_btn_cursorR.setToolTip(self.transl.tr('Move cut cursor to right'))
edit_btn_activate_all = QtWidgets.QPushButton(self.transl.tr('All'), self.main_frame)
edit_btn_activate_all.clicked.connect(self._on_edit_activate_all)
edit_btn_activate_all.setToolTip(self.transl.tr('Set all cuts to be active'))
edit_btn_deactivate_all = QtWidgets.QPushButton(self.transl.tr('None'), self.main_frame)
edit_btn_deactivate_all.clicked.connect(self._on_edit_deactivate_all)
edit_btn_deactivate_all.setToolTip(self.transl.tr('Set no cuts to be active'))
# Add the description line edit
self.le_description = qt_utils.ShadowTextLineEdit(
self.main_frame, self.transl.tr('Enter description here for template watermark'))
self.le_description.editingFinished.connect(self._on_description)
self.le_description.setAlignment(QtCore.Qt.AlignHCenter)
######################################################################
# Layout widgets in the main frame
######################################################################
# vbox contains all of the widgets in the main frame, positioned
# vertically
vbox = QtWidgets.QVBoxLayout()
# Add the figure canvas to the top
vbox.addWidget(self.fig.canvas)
# hbox contains all of the control widgets
# (everything but the canvas)
hbox = QtWidgets.QHBoxLayout()
# this grid contains all the lower-left input stuff
grid = QtWidgets.QGridLayout()
grid.addWidget(qt_utils.create_hline(), 0, 0, 2, 9, QtCore.Qt.AlignTop)
grid.addWidget(qt_utils.create_vline(), 0, 0, 9, 1)
# Add the board width label, board width input line edit,
# all stacked vertically on the left side.
grid.addWidget(self.le_board_width_label, 1, 1)
grid.addWidget(self.le_board_width, 2, 1)
grid.addWidget(qt_utils.create_vline(), 0, 2, 9, 1)
# Add the bit width label and its line edit
grid.addWidget(self.le_bit_width_label, 1, 3)
grid.addWidget(self.le_bit_width, 2, 3)
grid.addWidget(qt_utils.create_vline(), 0, 4, 9, 1)
# Add the bit depth label and its line edit
grid.addWidget(self.le_bit_depth_label, 1, 5)
grid.addWidget(self.le_bit_depth, 2, 5)
grid.addWidget(qt_utils.create_vline(), 0, 6, 9, 1)
# Add the bit angle label and its line edit
grid.addWidget(self.le_bit_angle_label, 1, 7)
grid.addWidget(self.le_bit_angle, 2, 7)
grid.addWidget(qt_utils.create_vline(), 0, 8, 9, 1)
grid.addWidget(qt_utils.create_hline(), 3, 0, 2, 9, QtCore.Qt.AlignTop)
grid.setRowStretch(2, 10)
# Add the wood combo boxes
grid.addWidget(self.cb_wood_label[0], 4, 1)
grid.addWidget(self.cb_wood_label[1], 4, 3)
grid.addWidget(self.cb_wood_label[2], 4, 5)
grid.addWidget(self.cb_wood_label[3], 4, 7)
grid.addWidget(self.cb_wood[0], 5, 1)
grid.addWidget(self.cb_wood[1], 5, 3)
grid.addWidget(self.cb_wood[2], 5, 5)
grid.addWidget(self.cb_wood[3], 5, 7)
# Add double* thickness line edits
grid.addWidget(self.le_boardm_label[0], 6, 5)
grid.addWidget(self.le_boardm_label[1], 6, 7)
grid.addWidget(self.le_boardm[0], 7, 5)
grid.addWidget(self.le_boardm[1], 7, 7)
grid.addWidget(qt_utils.create_hline(), 8, 0, 2, 9, QtCore.Qt.AlignTop)
hbox.addLayout(grid)
# Create the layout of the Equal spacing controls
hbox_es = QtWidgets.QHBoxLayout()
vbox_es_slider0 = QtWidgets.QVBoxLayout()
vbox_es_slider0.addWidget(self.es_slider0_label)
vbox_es_slider0.addWidget(self.es_slider0)
hbox_es.addLayout(vbox_es_slider0)
vbox_es_slider1 = QtWidgets.QVBoxLayout()
vbox_es_slider1.addWidget(self.es_slider1_label)
vbox_es_slider1.addWidget(self.es_slider1)
hbox_es.addLayout(vbox_es_slider1)
hbox_es.addWidget(self.cb_es_centered)
# Create the layout of the Variable spacing controls. Given only one
# item, this is overkill, but the coding allows us to add additional
# controls later.
# hbox_vs = QtWidgets.QVBoxLayout()
hbox_vs = QtWidgets.QHBoxLayout()
vbox_vs_cb = QtWidgets.QVBoxLayout()
vbox_vs_cb.addWidget(self.cb_vsfingers_label)
vbox_vs_cb.addWidget(self.cb_vsfingers)
hbox_vs.addLayout(vbox_vs_cb)
vbox_vs_slider0 = QtWidgets.QVBoxLayout()
vbox_vs_slider0.addWidget(self.vs_slider0_label)
vbox_vs_slider0.addWidget(self.vs_slider0)
hbox_vs.addLayout(vbox_vs_slider0)
hbox_vs.addWidget(self.cb_vs_inverted)
# Create the layout of the edit spacing controls
hbox_edit = QtWidgets.QHBoxLayout()
grid_edit = QtWidgets.QGridLayout()
grid_edit.addWidget(qt_utils.create_hline(), 0, 0, 2, 16, QtCore.Qt.AlignTop)
grid_edit.addWidget(qt_utils.create_hline(), 2, 0, 2, 16, QtCore.Qt.AlignTop)
grid_edit.addWidget(qt_utils.create_vline(), 0, 0, 6, 1)
label_active_cut_select = QtWidgets.QLabel(self.transl.tr('Active Cut Select'))
label_active_cut_select.setToolTip(self.transl.tr('Tools that select the active cuts'))
grid_edit.addWidget(label_active_cut_select, 1, 1, 1, 3, QtCore.Qt.AlignHCenter)
grid_edit.addWidget(edit_btn_toggle, 3, 1, 1, 2, QtCore.Qt.AlignHCenter)
grid_edit.addWidget(edit_btn_cursorL, 4, 1, QtCore.Qt.AlignRight)
grid_edit.addWidget(edit_btn_cursorR, 4, 2, QtCore.Qt.AlignLeft)
grid_edit.addWidget(edit_btn_activate_all, 3, 3)
grid_edit.addWidget(edit_btn_deactivate_all, 4, 3)
grid_edit.addWidget(qt_utils.create_vline(), 0, 4, 6, 1)
label_active_cut_ops = QtWidgets.QLabel(self.transl.tr('Active Cut Operators'))
label_active_cut_ops.setToolTip(self.transl.tr('Edit operations applied to active cuts'))
grid_edit.addWidget(label_active_cut_ops, 1, 5, 1, 10, QtCore.Qt.AlignHCenter)
grid_edit.addWidget(edit_move_label, 3, 5, 1, 2, QtCore.Qt.AlignHCenter)
grid_edit.addWidget(edit_btn_moveL, 4, 5, QtCore.Qt.AlignRight)
grid_edit.addWidget(edit_btn_moveR, 4, 6, QtCore.Qt.AlignLeft)
grid_edit.addWidget(qt_utils.create_vline(), 2, 7, 4, 1)
grid_edit.addWidget(edit_widen_label, 3, 8, 1, 2, QtCore.Qt.AlignHCenter)
grid_edit.addWidget(edit_btn_widenL, 4, 8, QtCore.Qt.AlignRight)
grid_edit.addWidget(edit_btn_widenR, 4, 9, QtCore.Qt.AlignLeft)
grid_edit.addWidget(qt_utils.create_vline(), 2, 10, 4, 1)
grid_edit.addWidget(edit_trim_label, 3, 11, 1, 2, QtCore.Qt.AlignHCenter)
grid_edit.addWidget(edit_btn_trimL, 4, 11, QtCore.Qt.AlignRight)
grid_edit.addWidget(edit_btn_trimR, 4, 12, QtCore.Qt.AlignLeft)
grid_edit.addWidget(qt_utils.create_vline(), 2, 13, 4, 1)
grid_edit.addWidget(edit_btn_add, 3, 14)
grid_edit.addWidget(edit_btn_del, 4, 14)
grid_edit.addWidget(qt_utils.create_vline(), 0, 15, 6, 1)
grid_edit.addWidget(qt_utils.create_hline(), 5, 0, 2, 16, QtCore.Qt.AlignTop)
grid_edit.setSpacing(5)
hbox_edit.addLayout(grid_edit)
hbox_edit.addStretch(1)
hbox_edit.addWidget(edit_btn_undo)
# Add the spacing layouts as Tabs
self.tabs_spacing = QtWidgets.QTabWidget()
tab_es = QtWidgets.QWidget()
tab_es.setLayout(hbox_es)
self.tabs_spacing.addTab(tab_es, self.transl.tr('Equal'))
tab_vs = QtWidgets.QWidget()
tab_vs.setLayout(hbox_vs)
self.tabs_spacing.addTab(tab_vs, self.transl.tr('Variable'))
tab_edit = QtWidgets.QWidget()
tab_edit.setLayout(hbox_edit)
self.tabs_spacing.addTab(tab_edit, self.transl.tr('Editor'))
self.tabs_spacing.currentChanged.connect(self._on_tabs_spacing)
tip = self.transl.tr('These tabs specify the layout algorithm for the cuts.')
self.tabs_spacing.setToolTip(tip)
# The tab indices should be set in the order they're defined, but this ensures it
self.equal_spacing_id = self.tabs_spacing.indexOf(tab_es)
self.var_spacing_id = self.tabs_spacing.indexOf(tab_vs)
self.edit_spacing_id = self.tabs_spacing.indexOf(tab_edit)
# set default spacing tab to Equal
self.spacing_index = self.equal_spacing_id
self.tabs_spacing.setCurrentIndex(self.spacing_index)
# either add the spacing Tabs to the right of the line edits
vbox_tabs = QtWidgets.QVBoxLayout()
vbox_tabs.addWidget(self.tabs_spacing)
vbox_tabs.addWidget(self.le_description)
vbox_tabs.addStretch(1)
hbox.addStretch(1)
hbox.addLayout(vbox_tabs)
vbox.addLayout(hbox)
# Lay it all out
self.main_frame.setLayout(vbox)
self.setCentralWidget(self.main_frame)
# Finalize some settings
self.cb_vsfingers.activated.connect(self._on_cb_vsfingers)
self.cb_vsfingers.highlighted.connect(self._on_cb_vsfingers)
self.cb_wood[0].activated.connect(self._on_wood0)
self.cb_wood[1].activated.connect(self._on_wood1)
self.cb_wood[2].activated.connect(self._on_wood2)
self.cb_wood[3].activated.connect(self._on_wood3)
self.cb_wood[0].highlighted.connect(self._on_wood0)
self.cb_wood[1].highlighted.connect(self._on_wood1)
self.cb_wood[2].highlighted.connect(self._on_wood2)
self.cb_wood[3].highlighted.connect(self._on_wood3)
self._on_wood(0)
self._on_wood(1)
self._on_wood(2)
self._on_wood(3)
self.update_tooltips()
def update_cb_vsfingers(self, vMin, vMax, value):
'''
Updates the combobox for Variable spacing Fingers.
'''
self.cb_vsfingers.clear()
for i in lrange(vMin, vMax + 1, 1):
self.cb_vsfingers.addItem(str(i))
i = self.cb_vsfingers.findText(str(value))
self.cb_vsfingers.setCurrentIndex(i)
def update_tooltips(self):
'''
[Re]sets the tool tips for widgets whose tips depend on user settings
'''
disable = ''
if self.spacing_index == self.edit_spacing_id:
disable = self.transl.tr(' <b>Cannot change if in Editor mode.</b>')
disable_double = disable
if not self.boards[2].active:
disable_double = self.transl.tr(
' <b>Cannot change unless "Double Board" is not NONE.</b>')
disable_dd = disable
if not self.boards[3].active:
disable_dd = self.transl.tr(
' <b>Cannot change unless "Double-Double Board" is not NONE.</b>')
self.le_board_width_label.setToolTip(self.doc.board_width() + disable)
self.le_board_width.setToolTip(self.doc.board_width() + disable)
self.le_bit_width_label.setToolTip(self.doc.bit_width() + disable)
self.le_bit_width.setToolTip(self.doc.bit_width() + disable)
self.le_bit_depth_label.setToolTip(self.doc.bit_depth() + disable)
self.le_bit_depth.setToolTip(self.doc.bit_depth() + disable)
self.le_bit_angle_label.setToolTip(self.doc.bit_angle() + disable)
self.le_bit_angle.setToolTip(self.doc.bit_angle() + disable)
self.cb_wood_label[0].setToolTip(self.doc.top_board() + disable)
self.cb_wood[0].setToolTip(self.doc.top_board() + disable)
self.cb_wood_label[1].setToolTip(self.doc.bottom_board() + disable)
self.cb_wood[1].setToolTip(self.doc.bottom_board() + disable)
self.cb_wood_label[2].setToolTip(self.doc.double_board() + disable)
self.cb_wood[2].setToolTip(self.doc.double_board() + disable)
self.cb_wood_label[3].setToolTip(self.doc.dd_board() + disable_double)
self.cb_wood[3].setToolTip(self.doc.dd_board() + disable_double)
self.le_boardm_label[0].setToolTip(self.doc.double_thickness() + disable_double)
self.le_boardm[0].setToolTip(self.doc.double_thickness() + disable_double)
self.le_boardm_label[1].setToolTip(self.doc.dd_thickness() + disable_dd)
self.le_boardm[1].setToolTip(self.doc.dd_thickness() + disable_dd)
self.es_slider0_label.setToolTip(self.doc.es_slider0())
self.es_slider0.setToolTip(self.doc.es_slider0())
self.es_slider1_label.setToolTip(self.doc.es_slider1())
self.es_slider1.setToolTip(self.doc.es_slider1())
self.cb_es_centered.setToolTip(self.doc.es_centered())
self.cb_vsfingers_label.setToolTip(self.doc.cb_vsfingers())
self.cb_vsfingers.setToolTip(self.doc.cb_vsfingers())
def create_status_bar(self):
'''
Creates a status message bar that is placed at the bottom of the
main frame.
'''
tt_message = self.transl.tr('Status of the last operation.')
tt_fit = self.transl.tr('Maximum overlap and gap for the current joint.'\
' Too much overlap will cause an interference fit,'\
' while too much gap will result in a loose-fitting joint.')
# Create the fonts and labels for each field
font = QtGui.QFont('Times', 14)
fm = QtGui.QFontMetrics(font)
fontL = QtGui.QFont(font)
fontL.setBold(True)
fmL = QtGui.QFontMetrics(fontL)
fit_text = self.transl.tr('Fit:')
fit = QtWidgets.QLabel(fit_text)
fit.setFont(fontL)
fit.setFixedWidth(fmL.width(fit_text))
fit.setToolTip(tt_fit)
status_text = self.transl.tr('Status:')
status = QtWidgets.QLabel(status_text)
status.setFont(fontL)
status.setFixedWidth(fmL.width(status_text))
status.setToolTip(tt_message)
# Create the label widgets that will change their text
style = QtWidgets.QFrame.Panel | QtWidgets.QFrame.Raised
self.status_message_label = QtWidgets.QLabel(self.transl.tr('MESSAGE'))
self.status_message_label.setFont(font)
self.status_message_label.setFrameStyle(style)
self.status_message_label.setToolTip(tt_message)
self.status_fit_label = QtWidgets.QLabel(self.transl.tr('FIT'))
w = fm.width(self.transl.tr('Max gap = 0.0000 mm Max overlap = 0.0000 mm'))
self.status_fit_label.setFixedWidth(w)
self.status_fit_label.setFont(font)
self.status_fit_label.setFrameStyle(style)
self.status_fit_label.setToolTip(tt_fit)
# Add labels to statusbar
self.statusbar = self.statusBar()
#self.status_message_label.setAlignment(QtCore.Qt.AlignRight)
self.statusbar.addPermanentWidget(fit, 1)
self.statusbar.addPermanentWidget(self.status_fit_label, 2)
self.statusbar.addPermanentWidget(status, 1)
self.statusbar.addPermanentWidget(self.status_message_label, 2)
self.status_message(self.transl.tr('Ready'))
def status_message(self, msg, warning=False, flash_len_ms=None):
'''
Displays a message to the status bar
'''
if warning:
style = 'background-color: red; color: white'
self.status_message_label.setStyleSheet(style)
else:
self.status_message_label.setStyleSheet('color: green')
self.status_message_label.setText(msg)
if flash_len_ms is not None:
QtCore.QTimer.singleShot(flash_len_ms, self._on_flash_status_off)
def status_fit(self):
'''
Updates the fit parameters in the status bar.
'''
if self.fig.geom is None:
return