Engauge Digitizer  2
StatusBar.cpp
1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5  ******************************************************************************************************/
6 
7 #include "EngaugeAssert.h"
8 #include "Logger.h"
9 #include <QFrame>
10 #include <QHBoxLayout>
11 #include <QLineEdit>
12 #include <QStatusBar>
13 #include <QTextEdit>
14 #include <QTimer>
15 #include <QWhatsThis>
16 #include "StatusBar.h"
17 #include "StatusBarMode.h"
18 #include "ZoomFactor.h"
19 #include "ZoomLabels.h"
20 
21 const int TEMPORARY_MESSAGE_LIFETIME = 5000; // Milliseconds. Two seconds is too fast even when the text is anticipated
22 
23 const int MIN_WIDTH_ZOOM = 110;
24 const int MIN_WIDTH_COMBO_UNITS = 160;
25 const int MIN_SIZE_EDIT_COORDS = 250; // Need lots of space in case date/time and degrees/minutes/seconds are used simultaneously
26 const int MAX_HEIGHT_EDIT_COORDS = 24;
27 
28 StatusBar::StatusBar(QStatusBar &statusBar) :
29  m_statusBar (statusBar),
30  m_statusBarMode (STATUS_BAR_MODE_ALWAYS),
31  m_timer (nullptr)
32 {
33  createZoomLabels ();
34  createZoom ();
35  createZoomMaps ();
36  createGroupUnits ();
37 
38  connect (&m_statusBar, SIGNAL (messageChanged (const QString &)), this, SLOT (slotStatusBarChanged (const QString &)));
39 
40  m_statusBar.setMaximumHeight (60);
41  m_statusBar.hide();
42 }
43 
44 StatusBar::~StatusBar ()
45 {
46  delete m_timer;
47 }
48 
49 void StatusBar::createGroupUnits ()
50 {
51  m_cmbUnits = new QComboBox;
52  m_cmbUnits->setEnabled (false); // Disabled until file is opened
53  m_cmbUnits->addItem (labelCoordsScreen (), QVariant (STATUS_BAR_UNITS_COORDS_SCREEN));
54  m_cmbUnits->addItem (labelCoordsGraph (), QVariant (STATUS_BAR_UNITS_COORDS_GRAPH));
55  m_cmbUnits->addItem (labelResolutionGraph (), QVariant (STATUS_BAR_UNITS_RESOLUTION_GRAPH));
56  m_cmbUnits->setCurrentText (labelCoordsGraph ());
57  m_cmbUnits->setMinimumWidth (MIN_WIDTH_COMBO_UNITS);
58  m_cmbUnits->setToolTip (tr ("Select cursor coordinate values to display."));
59  m_cmbUnits->setWhatsThis (tr("Select Cursor Coordinate Values\n\n"
60  "Values at cursor coordinates to display. Coordinates are in screen (pixels) or "
61  "graph units. Resolution (which is the number of graph units per pixel) is "
62  "in graph units. Graph units are only available after axis points have been defined."));
63  connect (m_cmbUnits, SIGNAL (activated(const QString &)), this, SLOT (slotComboUnits (const QString &))); // activated() ignores code changes
64 
65  m_editCoords = new QTextEdit;
66  m_editCoords->setEnabled (false); // Disabled until file is opened
67  m_editCoords->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
68  m_editCoords->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
69  m_editCoords->setMinimumSize (MIN_SIZE_EDIT_COORDS, MAX_HEIGHT_EDIT_COORDS);
70  m_editCoords->setMaximumHeight (MAX_HEIGHT_EDIT_COORDS);
71  m_editCoords->setReadOnly(true);
72  m_editCoords->setToolTip (tr ("Cursor coordinate values."));
73  m_editCoords->setWhatsThis (tr ("Cursor Coordinate Values\n\n"
74  "Values at cursor coordinates. Coordinates are in screen (pixels) or "
75  "graph units. Resolution (which is the number of graph units per pixel) is "
76  "in graph units. Graph units are only available after axis points have been defined."));
77 
78  m_groupUnits = new QFrame;
79  m_groupUnits->setFrameStyle (QFrame::Box);
80  QPalette palette;
81  palette.setColor (QPalette::Foreground, Qt::gray);
82  m_groupUnits->setPalette (palette);
83 
84  QHBoxLayout *groupLayout = new QHBoxLayout;
85  m_groupUnits->setLayout (groupLayout);
86  groupLayout->setContentsMargins (0, 0, 0, 0);
87  groupLayout->addWidget (m_cmbUnits);
88  groupLayout->addWidget (m_editCoords);
89  groupLayout->setMargin (2);
90 
91  m_statusBar.addPermanentWidget (m_groupUnits);
92 }
93 
94 void StatusBar::createZoom ()
95 {
96  m_cmbZoom = new QComboBox ();
97  m_cmbZoom->setEnabled (false); // Disabled until file is opened
98  m_cmbZoom->setMinimumWidth (MIN_WIDTH_ZOOM);
99  m_cmbZoom->addItem (*LABEL_ZOOM_16_TO_1);
100  m_cmbZoom->addItem (*LABEL_ZOOM_16_TO_1_FARTHER);
101  m_cmbZoom->addItem (*LABEL_ZOOM_8_TO_1_CLOSER);
102  m_cmbZoom->addItem (*LABEL_ZOOM_8_TO_1);
103  m_cmbZoom->addItem (*LABEL_ZOOM_8_TO_1_FARTHER);
104  m_cmbZoom->addItem (*LABEL_ZOOM_4_TO_1_CLOSER);
105  m_cmbZoom->addItem (*LABEL_ZOOM_4_TO_1);
106  m_cmbZoom->addItem (*LABEL_ZOOM_4_TO_1_FARTHER);
107  m_cmbZoom->addItem (*LABEL_ZOOM_2_TO_1_CLOSER);
108  m_cmbZoom->addItem (*LABEL_ZOOM_2_TO_1);
109  m_cmbZoom->addItem (*LABEL_ZOOM_2_TO_1_FARTHER);
110  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_1_CLOSER);
111  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_1);
112  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_1_FARTHER);
113  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_2_CLOSER);
114  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_2);
115  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_2_FARTHER);
116  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_4_CLOSER);
117  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_4);
118  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_4_FARTHER);
119  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_8_CLOSER);
120  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_8);
121  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_8_FARTHER);
122  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_16_CLOSER);
123  m_cmbZoom->addItem (*LABEL_ZOOM_1_TO_16);
124  m_cmbZoom->addItem (*LABEL_ZOOM_FILL);
125  m_cmbZoom->setCurrentText (*LABEL_ZOOM_1_TO_1);
126  m_cmbZoom->setMaximumWidth (80);
127  m_cmbZoom->setToolTip (tr ("Select zoom."));
128  m_cmbZoom->setWhatsThis (tr("Select Zoom\n\n"
129  "Points can be more accurately placed by zooming in."));
130  // Zoom combobox must use currentTextChanged rather than activated or else fill-zoom-at-startup never takes effect
131  connect (m_cmbZoom, SIGNAL (currentTextChanged(const QString &)), this, SLOT (slotComboZoom (const QString &)));
132 
133  m_statusBar.addPermanentWidget (m_cmbZoom);
134 }
135 
136 void StatusBar::createZoomLabels ()
137 {
138  LABEL_ZOOM_16_TO_1= new QString (tr ("16:1"));
139  LABEL_ZOOM_16_TO_1_FARTHER= new QString (tr ("16:1 farther"));
140  LABEL_ZOOM_8_TO_1_CLOSER= new QString (tr ("8:1 closer"));
141  LABEL_ZOOM_8_TO_1= new QString (tr ("8:1"));
142  LABEL_ZOOM_8_TO_1_FARTHER= new QString (tr ("8:1 farther"));
143  LABEL_ZOOM_4_TO_1_CLOSER= new QString (tr ("4:1 closer"));
144  LABEL_ZOOM_4_TO_1= new QString (tr ("4:1"));
145  LABEL_ZOOM_4_TO_1_FARTHER= new QString (tr ("4:1 farther"));
146  LABEL_ZOOM_2_TO_1_CLOSER= new QString (tr ("2:1 closer"));
147  LABEL_ZOOM_2_TO_1= new QString (tr ("2:1"));
148  LABEL_ZOOM_2_TO_1_FARTHER= new QString (tr ("2:1 farther"));
149  LABEL_ZOOM_1_TO_1_CLOSER= new QString (tr ("1:1 closer"));
150  LABEL_ZOOM_1_TO_1= new QString (tr ("1:1"));
151  LABEL_ZOOM_1_TO_1_FARTHER= new QString (tr ("1:1 farther"));
152  LABEL_ZOOM_1_TO_2_CLOSER= new QString (tr ("1:2 closer"));
153  LABEL_ZOOM_1_TO_2= new QString (tr ("1:2"));
154  LABEL_ZOOM_1_TO_2_FARTHER= new QString (tr ("1:2 farther"));
155  LABEL_ZOOM_1_TO_4_CLOSER= new QString (tr ("1:4 closer"));
156  LABEL_ZOOM_1_TO_4= new QString (tr ("1:4"));
157  LABEL_ZOOM_1_TO_4_FARTHER= new QString (tr ("1:4 farther"));
158  LABEL_ZOOM_1_TO_8_CLOSER= new QString (tr ("1:8 closer"));
159  LABEL_ZOOM_1_TO_8= new QString (tr ("1:8"));
160  LABEL_ZOOM_1_TO_8_FARTHER= new QString (tr ("1:8 farther"));
161  LABEL_ZOOM_1_TO_16_CLOSER= new QString (tr ("1:16 closer"));
162  LABEL_ZOOM_1_TO_16= new QString (tr ("1:16"));
163  LABEL_ZOOM_FILL= new QString (tr ("Fill"));
164  LABEL_ZOOM_PREVIOUS= new QString (tr ("Previous"));
165 }
166 
167 void StatusBar::createZoomMaps ()
168 {
169  m_zoomMapToLabel [ZOOM_16_TO_1] = *LABEL_ZOOM_16_TO_1;
170  m_zoomMapToLabel [ZOOM_16_TO_1_FARTHER] = *LABEL_ZOOM_16_TO_1_FARTHER;
171  m_zoomMapToLabel [ZOOM_8_TO_1_CLOSER] = *LABEL_ZOOM_8_TO_1_CLOSER;
172  m_zoomMapToLabel [ZOOM_8_TO_1] = *LABEL_ZOOM_8_TO_1;
173  m_zoomMapToLabel [ZOOM_8_TO_1_FARTHER] = *LABEL_ZOOM_8_TO_1_FARTHER;
174  m_zoomMapToLabel [ZOOM_4_TO_1_CLOSER] = *LABEL_ZOOM_4_TO_1_CLOSER;
175  m_zoomMapToLabel [ZOOM_4_TO_1] = *LABEL_ZOOM_4_TO_1;
176  m_zoomMapToLabel [ZOOM_4_TO_1_FARTHER] = *LABEL_ZOOM_4_TO_1_FARTHER;
177  m_zoomMapToLabel [ZOOM_2_TO_1_CLOSER] = *LABEL_ZOOM_2_TO_1_CLOSER;
178  m_zoomMapToLabel [ZOOM_2_TO_1] = *LABEL_ZOOM_2_TO_1;
179  m_zoomMapToLabel [ZOOM_2_TO_1_FARTHER] = *LABEL_ZOOM_2_TO_1_FARTHER;
180  m_zoomMapToLabel [ZOOM_1_TO_1_CLOSER] = *LABEL_ZOOM_1_TO_1_CLOSER;
181  m_zoomMapToLabel [ZOOM_1_TO_1] = *LABEL_ZOOM_1_TO_1;
182  m_zoomMapToLabel [ZOOM_1_TO_1_FARTHER] = *LABEL_ZOOM_1_TO_1_FARTHER;
183  m_zoomMapToLabel [ZOOM_1_TO_2_CLOSER] = *LABEL_ZOOM_1_TO_2_CLOSER;
184  m_zoomMapToLabel [ZOOM_1_TO_2] = *LABEL_ZOOM_1_TO_2;
185  m_zoomMapToLabel [ZOOM_1_TO_2_FARTHER] = *LABEL_ZOOM_1_TO_2_FARTHER;
186  m_zoomMapToLabel [ZOOM_1_TO_4_CLOSER] = *LABEL_ZOOM_1_TO_4_CLOSER;
187  m_zoomMapToLabel [ZOOM_1_TO_4] = *LABEL_ZOOM_1_TO_4;
188  m_zoomMapToLabel [ZOOM_1_TO_4_FARTHER] = *LABEL_ZOOM_1_TO_4_FARTHER;
189  m_zoomMapToLabel [ZOOM_1_TO_8_CLOSER] = *LABEL_ZOOM_1_TO_8_CLOSER;
190  m_zoomMapToLabel [ZOOM_1_TO_8] = *LABEL_ZOOM_1_TO_8;
191  m_zoomMapToLabel [ZOOM_1_TO_8_FARTHER] = *LABEL_ZOOM_1_TO_8_FARTHER;
192  m_zoomMapToLabel [ZOOM_1_TO_16_CLOSER] = *LABEL_ZOOM_1_TO_16_CLOSER;
193  m_zoomMapToLabel [ZOOM_1_TO_16] = *LABEL_ZOOM_1_TO_16;
194  m_zoomMapToLabel [ZOOM_FILL] = *LABEL_ZOOM_FILL;
195 
196  m_zoomMapFromLabel [*LABEL_ZOOM_16_TO_1] = ZOOM_16_TO_1;
197  m_zoomMapFromLabel [*LABEL_ZOOM_16_TO_1_FARTHER] = ZOOM_16_TO_1_FARTHER;
198  m_zoomMapFromLabel [*LABEL_ZOOM_8_TO_1_CLOSER] = ZOOM_8_TO_1_CLOSER;
199  m_zoomMapFromLabel [*LABEL_ZOOM_8_TO_1] = ZOOM_8_TO_1;
200  m_zoomMapFromLabel [*LABEL_ZOOM_8_TO_1_FARTHER] = ZOOM_8_TO_1_FARTHER;
201  m_zoomMapFromLabel [*LABEL_ZOOM_4_TO_1_CLOSER] = ZOOM_4_TO_1_CLOSER;
202  m_zoomMapFromLabel [*LABEL_ZOOM_4_TO_1] = ZOOM_4_TO_1;
203  m_zoomMapFromLabel [*LABEL_ZOOM_4_TO_1_FARTHER] = ZOOM_4_TO_1_FARTHER;
204  m_zoomMapFromLabel [*LABEL_ZOOM_2_TO_1_CLOSER] = ZOOM_2_TO_1_CLOSER;
205  m_zoomMapFromLabel [*LABEL_ZOOM_2_TO_1] = ZOOM_2_TO_1;
206  m_zoomMapFromLabel [*LABEL_ZOOM_2_TO_1_FARTHER] = ZOOM_2_TO_1_FARTHER;
207  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_1_CLOSER] = ZOOM_1_TO_1_CLOSER;
208  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_1] = ZOOM_1_TO_1;
209  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_1_FARTHER] = ZOOM_1_TO_1_FARTHER;
210  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_2_CLOSER] = ZOOM_1_TO_2_CLOSER;
211  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_2] = ZOOM_1_TO_2;
212  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_2_FARTHER] = ZOOM_1_TO_2_FARTHER;
213  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_4_CLOSER] = ZOOM_1_TO_4_CLOSER;
214  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_4] = ZOOM_1_TO_4;
215  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_4_FARTHER] = ZOOM_1_TO_4_FARTHER;
216  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_8_CLOSER] = ZOOM_1_TO_8_CLOSER;
217  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_8] = ZOOM_1_TO_8;
218  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_8_FARTHER] = ZOOM_1_TO_8_FARTHER;
219  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_16_CLOSER] = ZOOM_1_TO_16_CLOSER;
220  m_zoomMapFromLabel [*LABEL_ZOOM_1_TO_16] = ZOOM_1_TO_16;
221  m_zoomMapFromLabel [*LABEL_ZOOM_FILL] = ZOOM_FILL;
222 }
223 
224 QString StatusBar::labelCoordsGraph () const
225 {
226  return QString ("%1:").arg (QObject::tr ("Coordinates (graph)"));
227 }
228 
229 QString StatusBar::labelCoordsScreen () const
230 {
231  return QString ("%1:").arg (QObject::tr ("Coordinates (pixels)"));
232 }
233 
234 QString StatusBar::labelResolutionGraph () const
235 {
236  return QString ("%1:").arg (QObject::tr ("Resolution (graph)"));
237 }
238 
239 void StatusBar::setCoordinates (const QString &coordsScreen,
240  const QString &coordsGraph,
241  const QString &resolutionGraph)
242 {
243 // LOG4CPP_DEBUG_S ((*mainCat)) << "StatusBar::setCoordinates"
244 // << " screen=" << coordsScreen.toLatin1 ().data ()
245 // << " graph=" << coordsGraph.toLatin1 ().data ()
246 // << " resolution=" << resolutionGraph.toLatin1 ().data ();
247 
248  if (m_cmbUnits->isEnabled ()) {
249 
250  m_coordsScreen = coordsScreen;
251  m_coordsGraph = coordsGraph;
252  m_resolutionGraph = resolutionGraph;
253 
254  updateCoordsText();
255  }
256 }
257 
258 void StatusBar::setStatusBarMode(StatusBarMode statusBarMode)
259 {
260  m_statusBarMode = statusBarMode;
261  if (m_statusBarMode == STATUS_BAR_MODE_ALWAYS) {
262  m_statusBar.show();
263  } else {
264  m_statusBar.hide();
265  }
266 }
267 
268 void StatusBar::showTemporaryMessage(const QString &message)
269 {
270  LOG4CPP_DEBUG_S ((*mainCat)) << "StatusBar::showTemporaryMessage"
271  << " mode=" << statusBarModeToString (m_statusBarMode).toLatin1 ().data ()
272  << " message=" << message.toLatin1 ().data ();
273 
274  if (m_statusBarMode != STATUS_BAR_MODE_NEVER) {
275  if (m_statusBarMode == STATUS_BAR_MODE_TEMPORARY) {
276  // Calling m_statusBar.show here will have no effect since this is called while processing a signal. Use a timer to
277  // show the status bar as soon as possible
278  m_timer = new QTimer;
279  connect (m_timer, SIGNAL (timeout ()), this, SLOT (slotTimeout()));
280  m_timer->setSingleShot(true);
281  m_timer->start (0);
282  }
283  m_statusBar.showMessage (message, TEMPORARY_MESSAGE_LIFETIME);
284  }
285 }
286 
287 void StatusBar::slotComboUnits (const QString &text)
288 {
289  LOG4CPP_DEBUG_S ((*mainCat)) << "StatusBar::slotComboUnits text=" << text.toLatin1 ().data ();
290 
291  updateCoordsText();
292 }
293 
294 void StatusBar::slotComboZoom (const QString &text)
295 {
296  LOG4CPP_DEBUG_S ((*mainCat)) << "StatusBar::slotComboZoom text=" << text.toLatin1 ().data ();
297 
298  ENGAUGE_ASSERT (m_zoomMapFromLabel.contains (text));
299  ZoomFactor zoomFactor = m_zoomMapFromLabel [text];
300  emit signalZoom (zoomFactor);
301 }
302 
303 void StatusBar::slotStatusBarChanged(const QString &message)
304 {
305  LOG4CPP_DEBUG_S ((*mainCat)) << "StatusBar::slotStatusBarChanged message=" << message.toLatin1 ().data ();
306 
307  if (m_statusBarMode == STATUS_BAR_MODE_TEMPORARY) {
308  m_statusBar.hide();
309  }
310 }
311 
312 void StatusBar::slotTimeout()
313 {
314  LOG4CPP_INFO_S ((*mainCat)) << "StatusBar::slotTimeout";
315 
316  delete m_timer;
317  m_timer = nullptr;
318 
319  m_statusBar.show();
320 }
321 
322 void StatusBar::slotZoom(int zoom)
323 {
324  LOG4CPP_INFO_S ((*mainCat)) << "StatusBar::slotZoom zoom=" << zoom;
325 
326  // Show string for the numeric zoom value
327  ZoomFactor zoomFactor = static_cast<ZoomFactor> (zoom);
328  ENGAUGE_ASSERT (m_zoomMapToLabel.contains (zoomFactor));
329  m_cmbZoom->setCurrentText (m_zoomMapToLabel [zoomFactor]);
330 }
331 
332 void StatusBar::updateCoordsText()
333 {
334  if (m_cmbUnits->currentText() == labelCoordsScreen ()) {
335  m_editCoords->setText (m_coordsScreen);
336  } else if (m_cmbUnits->currentText() == labelCoordsGraph ()) {
337  m_editCoords->setText (m_coordsGraph);
338  } else {
339  m_editCoords->setText (m_resolutionGraph);
340  }
341 }
342 
344 {
345  if (!m_cmbUnits->isEnabled ()) {
346 
347  // First file has just been read in, so enable the widgets
348  m_cmbZoom->setEnabled (true);
349  m_cmbUnits->setEnabled (true);
350  m_editCoords->setEnabled (true);
351  }
352 }
void setStatusBarMode(StatusBarMode statusBarMode)
Set the status bar visibility mode.
Definition: StatusBar.cpp:258
StatusBar(QStatusBar &statusBar)
Single constructor that accepts the previously-constructed standard QStatusBar.
Definition: StatusBar.cpp:28
void setCoordinates(const QString &coordsScreen, const QString &coordsGraph, const QString &resolutionGraph)
Populate the coordinates fields. Unavailable values are empty. Html-encoding to highlight with colors...
Definition: StatusBar.cpp:239
void slotZoom(int)
Receive zoom selection from MainWindow.
Definition: StatusBar.cpp:322
void wakeUp()
Enable all widgets in the status bar. This is called just after a Document becomes active.
Definition: StatusBar.cpp:343
void signalZoom(int)
Send zoom factor, that was just selected in the status bar, to MainWindow.
StatusBarMode statusBarMode() const
Current mode for status bar visibility. This is tracked locally so this class knows when to hide/show...
Definition: StatusBar.h:45
void showTemporaryMessage(const QString &message)
Show temporary message in status bar. After a short interval the message will disappear.
Definition: StatusBar.cpp:268