kwave  18.07.70
ZoomToolBar.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  ZoomToolBar.cpp - Toolbar for zoom control
3  -------------------
4  begin : 2014-08-12
5  copyright : (C) 2014 by Thomas Eschenbacher
6  email : Thomas Eschenbacher <Thomas.Eschenbacher@gmx.de>
7 
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "config.h"
20 
21 #include <math.h>
22 
23 #include <QAction>
24 #include <QIcon>
25 
26 #include <KComboBox>
27 #include <KLocalizedString>
28 #include <KMainWindow>
29 
30 #include "libkwave/Selection.h"
31 #include "libkwave/SignalManager.h"
32 #include "libkwave/Utils.h"
33 
34 #include "libgui/MenuManager.h"
35 #include "libgui/Zoomable.h"
36 
37 #include "FileContext.h"
38 #include "ZoomToolBar.h"
39 
41 #define ZOOM_DATA_PREDEFINED (Qt::UserRole + 0)
42 
44 #define ZOOM_DATA_TIME (Qt::UserRole + 1)
45 
47 #define ELEMENTS_OF(__x__) (sizeof(__x__) / sizeof(__x__[0]))
48 
49 //***************************************************************************
50 Kwave::ZoomToolBar::ZoomToolBar(KMainWindow *parent, const QString &name)
51  :KToolBar(name, parent, true),
52  m_context(Q_NULLPTR),
53  m_action_zoomselection(Q_NULLPTR),
54  m_action_zoomin(Q_NULLPTR),
55  m_action_zoomout(Q_NULLPTR),
56  m_action_zoomnormal(Q_NULLPTR),
57  m_action_zoomall(Q_NULLPTR),
58  m_action_zoomselect(Q_NULLPTR),
59  m_zoomselect(Q_NULLPTR)
60 {
61  m_action_zoomselection = addAction(
62  QIcon::fromTheme(_("kwave_viewmag")),
63  i18n("Zoom to selection"),
64  this, SLOT(zoomSelection()));
65 
66  m_action_zoomin = addAction(
67  QIcon::fromTheme(_("kwave_zoom_in")),
68  i18n("Zoom in"),
69  this, SLOT(zoomIn()));
70 
71  m_action_zoomout = addAction(
72  QIcon::fromTheme(_("kwave_zoom_out")),
73  i18n("Zoom out"),
74  this, SLOT(zoomOut()));
75 
76  m_action_zoomnormal = addAction(
77  QIcon::fromTheme(_("kwave_zoom_original")),
78  i18n("Zoom to 100%"),
79  this, SLOT(zoomNormal()));
80 
81  m_action_zoomall = addAction(
82  QIcon::fromTheme(_("kwave_viewmagfit")),
83  i18n("Zoom to all"),
84  this, SLOT(zoomAll()));
85 
86  // zoom selection combo box
87  m_zoomselect = new KComboBox(this);
88  Q_ASSERT(m_zoomselect);
89  if (!m_zoomselect) return;
90 
91  m_zoomselect->setToolTip(i18n("Select zoom factor"));
92  m_zoomselect->setInsertPolicy(QComboBox::InsertAtTop);
93  m_zoomselect->setEditable(false);
94 
96  struct {
97  const QString text;
98  unsigned int ms;
99  } zoom_factors[] = {
100  { i18n("%1 ms", 1), 1L},
101  { i18n("%1 ms", 10), 10L},
102  { i18n("%1 ms", 100), 100L},
103  { i18n("%1 sec", 1), 1000L},
104  { i18n("%1 sec", 10), 10L*1000L},
105  { i18n("%1 sec", 30), 30L*1000L},
106  { i18n("%1 min", 1), 1L*60L*1000L},
107  { i18n("%1 min", 3), 3L*60L*1000L},
108  { i18n("%1 min", 5), 5L*60L*1000L},
109  { i18n("%1 min", 10), 10L*60L*1000L},
110  { i18n("%1 min", 30), 30L*60L*1000L},
111  { i18n("%1 min", 60), 60L*60L*1000L},
112  };
113 
114  for (unsigned int i = 0; i < ELEMENTS_OF(zoom_factors); i++) {
115  m_zoomselect->addItem(zoom_factors[i].text);
116  int index = m_zoomselect->count() - 1;
117  unsigned int time = zoom_factors[i].ms;
118  m_zoomselect->setItemData(index, QVariant(true), ZOOM_DATA_PREDEFINED);
119  m_zoomselect->setItemData(index, QVariant(time), ZOOM_DATA_TIME);
120  }
121 
122  m_action_zoomselect = addWidget(m_zoomselect);
123  connect(m_zoomselect, SIGNAL(activated(int)),
124  this, SLOT(selectZoom(int)));
125  connect(this, SIGNAL(sigCommand(QString)),
126  parent, SLOT(forwardCommand(QString)));
127 
128  int h = m_zoomselect->sizeHint().height();
129  m_zoomselect->setMinimumWidth(h * 5);
130  m_zoomselect->setFocusPolicy(Qt::FocusPolicy(Qt::ClickFocus | Qt::TabFocus));
131 
132  m_zoomselect->clearFocus();
133 }
134 
135 //***************************************************************************
137 {
138 }
139 
140 //***************************************************************************
142 {
143  if (context == m_context) return; // nothing to do
144  m_context = context;
145  updateToolbar();
146 }
147 
148 //***************************************************************************
150 {
151  if (context != m_context) return; // not of interest
152  contextSwitched(Q_NULLPTR);
153 }
154 
155 //***************************************************************************
157 {
158  bool have_signal = false;
159  bool have_selection = false;
160  bool is_closed = true;
161 
162  if (m_context) {
163  Kwave::SignalManager *signal_manager = m_context->signalManager();
164  Q_ASSERT(signal_manager);
165  if (!signal_manager) return;
166  have_signal = (signal_manager->tracks() != 0);
167  have_selection = (signal_manager->selection().length() != 0);
168  is_closed = signal_manager->isClosed();
169  }
170 
172  m_action_zoomselection->setEnabled(have_signal && have_selection);
173  if (m_action_zoomin)
174  m_action_zoomin->setEnabled(have_signal);
175  if (m_action_zoomout)
176  m_action_zoomout->setEnabled(have_signal);
178  m_action_zoomnormal->setEnabled(have_signal);
179  if (m_action_zoomall)
180  m_action_zoomall->setEnabled(have_signal);
182  m_action_zoomselect->setEnabled(have_signal);
183 
184  if (m_zoomselect && is_closed) {
185  for (int i = 0; i < m_zoomselect->count(); i++) {
186  QVariant v = m_zoomselect->itemData(i, ZOOM_DATA_PREDEFINED);
187  if (!v.isValid() || !v.toBool()) {
188  m_zoomselect->removeItem(i);
189  break;
190  }
191  }
192  m_zoomselect->insertItem(-1, _(" "));
193  m_zoomselect->setCurrentIndex(0);
194  }
195 }
196 
197 //***************************************************************************
199 {
200  if (!m_context) return;
201 
202  Kwave::SignalManager *signal_manager = m_context->signalManager();
203  Q_ASSERT(signal_manager);
204  Q_ASSERT(m_zoomselect);
205  if (!signal_manager) return;
206  if (!m_zoomselect) return;
207  if (index < 0) return;
208  if (index >= m_zoomselect->count()) return;
209 
210  QVariant v = m_zoomselect->itemData(index, ZOOM_DATA_TIME);
211  unsigned int ms = 1;
212  bool ok = false;
213  if (v.isValid()) ms = v.toUInt(&ok);
214  if (!ok) ms = 1;
215 
216  Kwave::Zoomable *zoomable = m_context->zoomable();
217  Q_ASSERT(zoomable);
218  if (!zoomable) return;
219 
220  const double rate = signal_manager->rate();
221  unsigned int width = zoomable->visibleWidth();
222  Q_ASSERT(width > 1);
223  if (width <= 1) width = 2;
224  const double new_zoom = rint(((rate * ms) / 1.0E3) -1 ) /
225  static_cast<double>(width - 1);
226  zoomable->setZoom(new_zoom);
227 
228  // force the zoom factor to be set, maybe the current selection
229  // has been changed/corrected to the previous value so that we
230  // don't get a signal.
231  setZoomInfo(m_context, zoomable->zoom());
232 }
233 
234 //***************************************************************************
236 {
237  if (!m_context || (context != m_context)) return;
238 
239  Kwave::SignalManager *signal_manager = m_context->signalManager();
240  Kwave::Zoomable *zoomable = m_context->zoomable();
241  Q_ASSERT(zoom >= 0);
242  Q_ASSERT(m_zoomselect);
243  if (zoom <= 0.0) return; // makes no sense or signal is empty
244  if (!m_zoomselect) return;
245 
246  double rate = (signal_manager) ? signal_manager->rate() : 0.0;
247  double ms = ((rate > 0) && (zoomable)) ?
248  (((zoomable->visibleSamples()) * 1E3) / rate) : 0.0;
249 
250  QString strZoom;
251  if ((signal_manager) && (signal_manager->tracks())) {
252  if (rate > 0) {
253  // time display mode
254  int s = Kwave::toInt(ms) / 1000;
255  int m = s / 60;
256 
257  if (ms >= 60*1000) {
258  strZoom = strZoom.sprintf("%02d:%02d min", m, s % 60);
259  } else if (ms >= 1000) {
260  strZoom = strZoom.sprintf("%d sec", s);
261  } else if (ms >= 1) {
262  strZoom = strZoom.sprintf("%d ms",
263  Kwave::toInt(round(ms)));
264  } else if (ms >= 0.01) {
265  strZoom = strZoom.sprintf("%0.3g ms", ms);
266  }
267  } else {
268  // percent mode
269  double percent = 100.0 / zoom;
270  strZoom = Kwave::zoom2string(percent);
271  }
272  }
273 
274  m_zoomselect->blockSignals(true);
275 
276  // if the text is equal to an entry in the current list -> keep it
277  if (m_zoomselect->contains(strZoom)) {
278  // select existing entry, string match
279  m_zoomselect->setCurrentIndex(m_zoomselect->findText(strZoom));
280  } else {
281  // remove user defined entries and scan for more or less exact match
282  int i = 0;
283  int match = -1;
284  while (i < m_zoomselect->count()) {
285  QVariant v = m_zoomselect->itemData(i, ZOOM_DATA_PREDEFINED);
286  if (!v.isValid() || !v.toBool()) {
287  m_zoomselect->removeItem(i);
288  } else {
289  QVariant vz = m_zoomselect->itemData(i, ZOOM_DATA_TIME);
290  bool ok = false;
291  double t = vz.toDouble(&ok);
292  if (ok && (t > 0) && fabs(1 - (t / ms)) < (1.0 / 60.0)) {
293  match = i;
294  }
295  i++;
296  }
297  }
298 
299  if (match >= 0) {
300  // use an exact match from the list
301  i = match;
302  } else if (rate > 0) {
303  // time mode:
304  // find the best index where to insert the new user defined value
305  for (i = 0; i < m_zoomselect->count(); ++i) {
306  QVariant v = m_zoomselect->itemData(i, ZOOM_DATA_TIME);
307  bool ok = false;
308  double t = v.toDouble(&ok);
309  if (!ok) continue;
310  if (t > ms) break;
311  }
312  m_zoomselect->insertItem(i, strZoom);
313  m_zoomselect->setItemData(i, QVariant(ms), ZOOM_DATA_TIME);
314  } else {
315  // percent mode -> just insert at top
316  m_zoomselect->insertItem(-1, strZoom);
317  i = 0;
318  }
319  m_zoomselect->setCurrentIndex(i);
320  }
321 
322  m_zoomselect->blockSignals(false);
323 }
324 
325 //***************************************************************************
326 //***************************************************************************
void setZoomInfo(Kwave::FileContext *context, double zoom)
virtual ~ZoomToolBar()
QAction * m_action_zoomout
Definition: ZoomToolBar.h:127
void contextDestroyed(Kwave::FileContext *context)
virtual sample_index_t visibleSamples() const =0
Kwave::Selection & selection()
unsigned int tracks()
QString Q_DECL_EXPORT zoom2string(double percent)
Definition: Utils.cpp:46
#define ZOOM_DATA_TIME
Definition: ZoomToolBar.cpp:44
QAction * m_action_zoomselect
Definition: ZoomToolBar.h:136
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
virtual int visibleWidth() const =0
sample_index_t length() const
Definition: Selection.h:66
const char name[16]
Definition: memcpy.c:510
#define ELEMENTS_OF(__x__)
Definition: ZoomToolBar.cpp:47
virtual double zoom() const =0
QAction * m_action_zoomin
Definition: ZoomToolBar.h:124
QAction * m_action_zoomall
Definition: ZoomToolBar.h:133
QAction * m_action_zoomselection
Definition: ZoomToolBar.h:121
void selectZoom(int index)
int toInt(T x)
Definition: Utils.h:127
double rate() const
ZoomToolBar(KMainWindow *parent, const QString &name)
Definition: ZoomToolBar.cpp:50
void contextSwitched(Kwave::FileContext *context)
virtual void setZoom(double factor)=0
Kwave::Zoomable * zoomable() const
#define ZOOM_DATA_PREDEFINED
Definition: ZoomToolBar.cpp:41
#define _(m)
Definition: memcpy.c:66
KComboBox * m_zoomselect
Definition: ZoomToolBar.h:139
Kwave::SignalManager * signalManager() const
Kwave::FileContext * m_context
Definition: ZoomToolBar.h:118
QAction * m_action_zoomnormal
Definition: ZoomToolBar.h:130
void sigCommand(const QString &command)