mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-11 08:07:24 -05:00
Closes Issue #33.
Adds Spectral/Waterfall display zoom feature with mouse dragging and zoom window indicator. Resolves issues with correct display and spacing of frequency labels and tick lines display in the overlay panel.
This commit is contained in:
@@ -28,13 +28,15 @@ import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import map.MapPanel;
|
||||
import message.Message;
|
||||
import map.MapService;
|
||||
import module.decode.event.CallEventPanel;
|
||||
import module.decode.event.MessageActivityPanel;
|
||||
import module.decode.state.ChannelList;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import sample.Listener;
|
||||
import playlist.PlaylistManager;
|
||||
import settings.SettingsManager;
|
||||
import spectrum.ChannelSpectrumPanel;
|
||||
import audio.AudioManager;
|
||||
import audio.AudioPanel;
|
||||
|
||||
import com.jidesoft.swing.JideSplitPane;
|
||||
@@ -62,13 +64,32 @@ public class ControllerPanel extends JPanel
|
||||
protected JideSplitPane mSystemControlSplitPane;
|
||||
|
||||
protected JTable mChannelActivityTable = new JTable();
|
||||
protected ResourceManager mResourceManager;
|
||||
private AudioPanel mAudioPanel;
|
||||
private MapPanel mMapPanel;
|
||||
|
||||
public ControllerPanel( ResourceManager resourceManager )
|
||||
private ChannelManager mChannelManager;
|
||||
private ConfigurationControllerModel mController;
|
||||
protected SettingsManager mSettingsManager;
|
||||
|
||||
public ControllerPanel( AudioManager audioManager,
|
||||
ConfigurationControllerModel controller,
|
||||
ChannelManager channelManager,
|
||||
MapService mapService,
|
||||
PlaylistManager playlistManager,
|
||||
SettingsManager settingsManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
mChannelManager = channelManager;
|
||||
mController = controller;
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
mAudioPanel = new AudioPanel( mSettingsManager, audioManager );
|
||||
|
||||
mMapPanel = new MapPanel( mapService, mSettingsManager, mChannelManager );
|
||||
|
||||
mCallEventPanel = new CallEventPanel( mSettingsManager );
|
||||
|
||||
mChannelStateList = new ChannelList( playlistManager, mSettingsManager );
|
||||
|
||||
mCallEventPanel = new CallEventPanel( resourceManager.getSettingsManager() );
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -80,8 +101,8 @@ public class ControllerPanel extends JPanel
|
||||
|
||||
//System Configuration View and Editor
|
||||
mConfigurationEditor = new ConfigurationEditor();
|
||||
mSystemControlViewPanel =
|
||||
new ConfigurationTreePanel( mResourceManager.getController() );
|
||||
|
||||
mSystemControlViewPanel = new ConfigurationTreePanel( mController );
|
||||
mSystemControlViewPanel.addTreeSelectionListener( mConfigurationEditor );
|
||||
|
||||
mSystemControlSplitPane = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
|
||||
@@ -89,7 +110,7 @@ public class ControllerPanel extends JPanel
|
||||
mSystemControlSplitPane.add( mSystemControlViewPanel );
|
||||
mSystemControlSplitPane.add( mConfigurationEditor );
|
||||
|
||||
mChannelSpectrumPanel = new ChannelSpectrumPanel( mResourceManager );
|
||||
mChannelSpectrumPanel = new ChannelSpectrumPanel( mSettingsManager );
|
||||
|
||||
//Tabbed View - configuration, calls, messages, map
|
||||
mTabbedPane = new JideTabbedPane();
|
||||
@@ -127,37 +148,23 @@ public class ControllerPanel extends JPanel
|
||||
/**
|
||||
* Add mapping services and map panel to a new tab
|
||||
*/
|
||||
|
||||
/* Add Map Service as message listener to receive all messages */
|
||||
mResourceManager.getChannelManager().addListener(
|
||||
(Listener<Message>)mResourceManager.getMapService() );
|
||||
mTabbedPane.addTab( "Map", mMapPanel );
|
||||
|
||||
MapPanel mapPanel = new MapPanel( mResourceManager );
|
||||
mTabbedPane.addTab( "Map", mapPanel );
|
||||
|
||||
|
||||
/* Channel state list */
|
||||
mChannelStateList = new ChannelList( mResourceManager.getPlaylistManager(),
|
||||
mResourceManager.getSettingsManager() );
|
||||
|
||||
/* Register each of the components to receive channel events when the
|
||||
* channels are selected or change */
|
||||
ChannelManager channelManager = mResourceManager.getChannelManager();
|
||||
channelManager.addListener( mCallEventPanel );
|
||||
channelManager.addListener( mChannelStateList );
|
||||
channelManager.addListener( mChannelSpectrumPanel );
|
||||
channelManager.addListener( mMessageActivityPanel );
|
||||
mChannelManager.addListener( mCallEventPanel );
|
||||
mChannelManager.addListener( mChannelStateList );
|
||||
mChannelManager.addListener( mChannelSpectrumPanel );
|
||||
mChannelManager.addListener( mMessageActivityPanel );
|
||||
|
||||
JScrollPane channelStateListScroll = new JScrollPane();
|
||||
channelStateListScroll.getViewport().setView( mChannelStateList );
|
||||
channelStateListScroll.setPreferredSize( new Dimension( 200, 300 ) );
|
||||
|
||||
AudioPanel audioPanel = new AudioPanel( mResourceManager.getSettingsManager(),
|
||||
mResourceManager.getAudioManager() );
|
||||
|
||||
JideSplitPane audioChannelListSplit = new JideSplitPane( JideSplitPane.VERTICAL_SPLIT );
|
||||
audioChannelListSplit.setDividerSize( 5 );
|
||||
audioChannelListSplit.add( audioPanel );
|
||||
audioChannelListSplit.add( mAudioPanel );
|
||||
audioChannelListSplit.add( channelStateListScroll );
|
||||
|
||||
JideSplitPane channelSplit = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
|
||||
@@ -170,6 +177,6 @@ public class ControllerPanel extends JPanel
|
||||
|
||||
public ConfigurationControllerModel getController()
|
||||
{
|
||||
return mResourceManager.getController();
|
||||
return mController;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,30 +38,34 @@ import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSeparator;
|
||||
|
||||
import map.MapService;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import playlist.PlaylistManager;
|
||||
import properties.SystemProperties;
|
||||
import settings.SettingsManager;
|
||||
import source.tuner.Tuner;
|
||||
import source.tuner.TunerSelectionListener;
|
||||
import spectrum.SpectralDisplayPanel;
|
||||
import util.TimeStamp;
|
||||
import audio.AudioManager;
|
||||
|
||||
import com.jidesoft.swing.JideSplitPane;
|
||||
|
||||
import controller.ConfigurationControllerModel;
|
||||
import controller.ControllerPanel;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.ChannelManager;
|
||||
|
||||
public class SDRTrunk
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( SDRTrunk.class );
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
private ControllerPanel mControllerPanel;
|
||||
private SpectralDisplayPanel mSpectralPanel;
|
||||
private JFrame mMainGui = new JFrame();
|
||||
@@ -73,8 +77,8 @@ public class SDRTrunk
|
||||
mLog.info( "" );
|
||||
mLog.info( "" );
|
||||
mLog.info( "*******************************************************************" );
|
||||
mLog.info( "**** SDRTrunk: a trunked radio and digital decoding application ***" );
|
||||
mLog.info( "**** website: https://code.google.com/p/sdrtrunk ***" );
|
||||
mLog.info( "**** sdrtrunk: a trunked radio and digital decoding application ***" );
|
||||
mLog.info( "**** website: https://github.com/dsheirer/sdrtrunk ***" );
|
||||
mLog.info( "*******************************************************************" );
|
||||
mLog.info( "" );
|
||||
mLog.info( "" );
|
||||
@@ -97,8 +101,24 @@ public class SDRTrunk
|
||||
* Construct the resource manager now, so that it can use the system
|
||||
* properties that were just loaded
|
||||
*/
|
||||
mResourceManager = new ResourceManager();
|
||||
ResourceManager resource = new ResourceManager();
|
||||
|
||||
//TODO: get rid of resource manager ... below is start of breaking out
|
||||
//the encapsulated pieces from the resource manager
|
||||
|
||||
AudioManager audio = resource.getAudioManager();
|
||||
ChannelManager channel = resource.getChannelManager();
|
||||
ConfigurationControllerModel controller = resource.getController();
|
||||
MapService map = resource.getMapService();
|
||||
PlaylistManager playlist = resource.getPlaylistManager();
|
||||
SettingsManager settings = resource.getSettingsManager();
|
||||
|
||||
mControllerPanel = new ControllerPanel( audio, controller, channel,
|
||||
map, playlist, settings );
|
||||
|
||||
mSpectralPanel = new SpectralDisplayPanel( channel, controller,
|
||||
playlist, settings );
|
||||
|
||||
mTitle = getTitle();
|
||||
|
||||
//Initialize the GUI
|
||||
@@ -140,17 +160,6 @@ public class SDRTrunk
|
||||
"[grow,fill]",
|
||||
"[grow,fill]") );
|
||||
|
||||
mControllerPanel = new ControllerPanel( mResourceManager );
|
||||
|
||||
mSpectralPanel = new SpectralDisplayPanel( mResourceManager );
|
||||
|
||||
//Register spectral panel to receive tuner selection events
|
||||
mControllerPanel.getController()
|
||||
.addListener( (TunerSelectionListener)mSpectralPanel );
|
||||
|
||||
//Add spectrum panel to receive channel change events
|
||||
mResourceManager.getChannelManager().addListener( mSpectralPanel );
|
||||
|
||||
//init() the controller to load tuners and playlists
|
||||
mControllerPanel.getController().init();
|
||||
|
||||
@@ -382,7 +391,7 @@ public class SDRTrunk
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "SDRTrunk" );
|
||||
sb.append( "sdrtrunk" );
|
||||
|
||||
try( BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader( this.getClass()
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.EventQueue;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import message.Message;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import org.jdesktop.swingx.JXMapViewer;
|
||||
@@ -31,9 +32,10 @@ import org.jdesktop.swingx.mapviewer.DefaultTileFactory;
|
||||
import org.jdesktop.swingx.mapviewer.GeoPosition;
|
||||
import org.jdesktop.swingx.mapviewer.TileFactoryInfo;
|
||||
|
||||
import sample.Listener;
|
||||
import settings.MapViewSetting;
|
||||
import settings.SettingsManager;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.ChannelManager;
|
||||
|
||||
public class MapPanel extends JPanel implements PlottableUpdateListener
|
||||
{
|
||||
@@ -44,11 +46,17 @@ public class MapPanel extends JPanel implements PlottableUpdateListener
|
||||
private JXMapViewer mMapViewer = new JXMapViewer();
|
||||
private PlottableEntityPainter mMapPainter;
|
||||
|
||||
public MapPanel( ResourceManager resourceManager )
|
||||
public MapPanel( MapService mapService,
|
||||
SettingsManager settingsManager,
|
||||
ChannelManager channelManager )
|
||||
{
|
||||
mSettingsManager = resourceManager.getSettingsManager();
|
||||
mMapService = resourceManager.getMapService();
|
||||
mSettingsManager = settingsManager;
|
||||
mMapService = mapService;
|
||||
mMapPainter = new PlottableEntityPainter( mSettingsManager );
|
||||
|
||||
/* Add Map Service as message listener to receive all messages */
|
||||
channelManager.addListener( (Listener<Message>)mMapService );
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeListener;
|
||||
import spectrum.SpectrumFrame;
|
||||
import controller.BaseNode;
|
||||
import controller.ResourceManager;
|
||||
|
||||
public class TunerNode extends BaseNode implements FrequencyChangeListener
|
||||
{
|
||||
@@ -112,9 +113,11 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
SpectrumFrame frame =
|
||||
new SpectrumFrame( getModel().getResourceManager(),
|
||||
getTuner() );
|
||||
ResourceManager rm = getModel().getResourceManager();
|
||||
|
||||
SpectrumFrame frame = new SpectrumFrame( rm.getChannelManager(),
|
||||
rm.getController(), rm.getPlaylistManager(),
|
||||
rm.getSettingsManager(), getTuner() );
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import settings.ColorSetting;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import controller.ResourceManager;
|
||||
import settings.SettingsManager;
|
||||
|
||||
public class ChannelOverlayPanel extends JPanel implements SettingChangeListener
|
||||
{
|
||||
@@ -56,16 +56,21 @@ public class ChannelOverlayPanel extends JPanel implements SettingChangeListener
|
||||
//the frequency labels
|
||||
private float mSpectrumInset = 20.0f;
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
private SettingsManager mSettingsManager;
|
||||
|
||||
/**
|
||||
* Translucent overlay panel for displaying channel configurations,
|
||||
* processing channels, selected channels, frequency labels and lines, and
|
||||
* a cursor with a frequency readout.
|
||||
*/
|
||||
public ChannelOverlayPanel( ResourceManager resourceManager )
|
||||
public ChannelOverlayPanel( SettingsManager settingsManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.addListener( this );
|
||||
}
|
||||
|
||||
//Set the background transparent, so the spectrum display can be seen
|
||||
setOpaque( false );
|
||||
@@ -76,7 +81,12 @@ public class ChannelOverlayPanel extends JPanel implements SettingChangeListener
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mResourceManager = null;
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.removeListener( this );
|
||||
}
|
||||
|
||||
mSettingsManager = null;
|
||||
}
|
||||
|
||||
public void setCursorLocation( Point point )
|
||||
@@ -112,9 +122,7 @@ public class ChannelOverlayPanel extends JPanel implements SettingChangeListener
|
||||
*/
|
||||
private Color getColor( ColorSettingName name )
|
||||
{
|
||||
ColorSetting setting =
|
||||
mResourceManager.getSettingsManager()
|
||||
.getColorSetting( name );
|
||||
ColorSetting setting = mSettingsManager.getColorSetting( name );
|
||||
|
||||
return setting.getColor();
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class ChannelSpectrumPanel extends JPanel
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
// private ResourceManager mResourceManager;
|
||||
private DFTProcessor mDFTProcessor = new DFTProcessor( SampleType.REAL );
|
||||
private DFTResultsConverter mDFTConverter = new RealDecibelConverter();
|
||||
private JLayeredPane mLayeredPane;
|
||||
@@ -78,15 +78,22 @@ public class ChannelSpectrumPanel extends JPanel
|
||||
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true );
|
||||
|
||||
private AtomicBoolean mEnabled = new AtomicBoolean();
|
||||
|
||||
private SettingsManager mSettingsManager;
|
||||
|
||||
public ChannelSpectrumPanel( ResourceManager resourceManager )
|
||||
public ChannelSpectrumPanel( SettingsManager settingsManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
mResourceManager.getSettingsManager().addListener( this );
|
||||
mSpectrumPanel = new SpectrumPanel( mResourceManager );
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.addListener( this );
|
||||
}
|
||||
|
||||
mSpectrumPanel = new SpectrumPanel( mSettingsManager );
|
||||
mSpectrumPanel.setAveraging( 1 );
|
||||
|
||||
mOverlayPanel = new ChannelOverlayPanel( mResourceManager );
|
||||
mOverlayPanel = new ChannelOverlayPanel( mSettingsManager );
|
||||
mDFTProcessor.addConverter( mDFTConverter );
|
||||
mDFTConverter.addListener( mSpectrumPanel );
|
||||
|
||||
@@ -103,7 +110,12 @@ public class ChannelSpectrumPanel extends JPanel
|
||||
|
||||
mDFTProcessor.dispose();
|
||||
|
||||
mResourceManager = null;
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.removeListener( this );
|
||||
}
|
||||
|
||||
mSettingsManager = null;
|
||||
mCurrentChannel = null;
|
||||
mDFTProcessor = null;
|
||||
mSpectrumPanel = null;
|
||||
@@ -338,21 +350,19 @@ public class ChannelSpectrumPanel extends JPanel
|
||||
*/
|
||||
JMenu colorMenu = new JMenu( "Color" );
|
||||
|
||||
SettingsManager sm = mResourceManager.getSettingsManager();
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_CURSOR ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_LINE ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_BACKGROUND ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_GRADIENT_BOTTOM ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_GRADIENT_TOP ) );
|
||||
|
||||
contextMenu.add( colorMenu );
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,6 +17,7 @@
|
||||
******************************************************************************/
|
||||
package spectrum;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
@@ -24,6 +25,7 @@ import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.geom.Line2D;
|
||||
@@ -41,14 +43,15 @@ import settings.ColorSetting;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import settings.SettingsManager;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeListener;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ChannelEvent;
|
||||
import controller.channel.ChannelEventListener;
|
||||
import controller.channel.ChannelManager;
|
||||
|
||||
public class OverlayPanel extends JPanel
|
||||
implements ChannelEventListener,
|
||||
@@ -60,8 +63,20 @@ public class OverlayPanel extends JPanel
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( OverlayPanel.class );
|
||||
|
||||
private final static RenderingHints RENDERING_HINTS =
|
||||
new RenderingHints( RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON );
|
||||
|
||||
static
|
||||
{
|
||||
RENDERING_HINTS.put( RenderingHints.KEY_RENDERING,
|
||||
RenderingHints.VALUE_RENDER_QUALITY );
|
||||
}
|
||||
|
||||
private final static BasicStroke DASHED_STROKE = new BasicStroke(0.8f,
|
||||
BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 5.0f, new float[] {5.0f}, 0.0f);
|
||||
|
||||
private static DecimalFormat CURSOR_FORMAT = new DecimalFormat( "000.00000" );
|
||||
private DecimalFormat mFrequencyFormat = new DecimalFormat( "0.0" );
|
||||
private long mFrequency = 0;
|
||||
private int mBandwidth = 0;
|
||||
private Point mCursorLocation = new Point( 0, 0 );
|
||||
@@ -92,18 +107,31 @@ public class OverlayPanel extends JPanel
|
||||
//Defines the offset at the bottom of the spectral display to account for
|
||||
//the frequency labels
|
||||
private double mSpectrumInset = 20.0d;
|
||||
private LabelSizeMonitor mLabelSizeMonitor = new LabelSizeMonitor();
|
||||
private LabelSizeManager mLabelSizeMonitor = new LabelSizeManager();
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
|
||||
private SettingsManager mSettingsManager;
|
||||
private ChannelManager mChannelManager;
|
||||
/**
|
||||
* Translucent overlay panel for displaying channel configurations,
|
||||
* processing channels, selected channels, frequency labels and lines, and
|
||||
* a cursor with a frequency readout.
|
||||
*/
|
||||
public OverlayPanel( ResourceManager resourceManager )
|
||||
public OverlayPanel( SettingsManager settingsManager,
|
||||
ChannelManager channelManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.addListener( this );
|
||||
}
|
||||
|
||||
mChannelManager = channelManager;
|
||||
|
||||
if( mChannelManager != null )
|
||||
{
|
||||
mChannelManager.addListener( this );
|
||||
}
|
||||
|
||||
addComponentListener( mLabelSizeMonitor );
|
||||
|
||||
@@ -116,12 +144,27 @@ public class OverlayPanel extends JPanel
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
if( mChannelManager != null )
|
||||
{
|
||||
mChannelManager.removeListener( this );
|
||||
}
|
||||
|
||||
mChannelManager = null;
|
||||
|
||||
mChannels.clear();
|
||||
mVisibleChannels.clear();
|
||||
|
||||
mResourceManager = null;
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.removeListener( this );
|
||||
}
|
||||
|
||||
mSettingsManager = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets/changes the DFT bin size
|
||||
*/
|
||||
public void setDFTSize( DFTSize size )
|
||||
{
|
||||
mDFTSize = size;
|
||||
@@ -160,13 +203,20 @@ public class OverlayPanel extends JPanel
|
||||
* 3 8x Zoom
|
||||
* 4 16x Zoom
|
||||
* 5 32x Zoom
|
||||
* 6 64x Zoom
|
||||
*
|
||||
* @param zoom level, 0 - 5.
|
||||
* @param zoom level, 0 - 6.
|
||||
* @param offset into the FFT bins for start zoom window
|
||||
*/
|
||||
public void setZoom( int zoom, int offset )
|
||||
public void setZoom( int zoom )
|
||||
{
|
||||
mZoom = zoom;
|
||||
|
||||
mLabelSizeMonitor.update();
|
||||
}
|
||||
|
||||
public void setZoomWindowOffset( int offset )
|
||||
{
|
||||
mDFTZoomWindowOffset = offset;
|
||||
}
|
||||
|
||||
@@ -197,9 +247,7 @@ public class OverlayPanel extends JPanel
|
||||
*/
|
||||
private Color getColor( ColorSettingName name )
|
||||
{
|
||||
ColorSetting setting =
|
||||
mResourceManager.getSettingsManager()
|
||||
.getColorSetting( name );
|
||||
ColorSetting setting = mSettingsManager.getColorSetting( name );
|
||||
|
||||
return setting.getColor();
|
||||
}
|
||||
@@ -252,14 +300,7 @@ public class OverlayPanel extends JPanel
|
||||
Graphics2D graphics = (Graphics2D) g;
|
||||
graphics.setBackground( mColorSpectrumBackground );
|
||||
|
||||
RenderingHints renderHints =
|
||||
new RenderingHints( RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON );
|
||||
|
||||
renderHints.put( RenderingHints.KEY_RENDERING,
|
||||
RenderingHints.VALUE_RENDER_QUALITY );
|
||||
|
||||
graphics.setRenderingHints( renderHints );
|
||||
graphics.setRenderingHints( RENDERING_HINTS );
|
||||
|
||||
drawFrequencies( graphics );
|
||||
drawChannels( graphics );
|
||||
@@ -279,7 +320,7 @@ public class OverlayPanel extends JPanel
|
||||
mColorSpectrumCursor );
|
||||
|
||||
String frequency = CURSOR_FORMAT.format(
|
||||
getFrequencyFromAxis( mCursorLocation.getX() ) / 1000000.0D );
|
||||
getFrequencyFromAxis( mCursorLocation.getX() ) / 1E6D );
|
||||
|
||||
graphics.drawString( frequency ,
|
||||
mCursorLocation.x + 5,
|
||||
@@ -298,26 +339,28 @@ public class OverlayPanel extends JPanel
|
||||
*/
|
||||
private void drawFrequencies( Graphics2D graphics )
|
||||
{
|
||||
Stroke currentStroke = graphics.getStroke();
|
||||
|
||||
graphics.setStroke( DASHED_STROKE );
|
||||
|
||||
long minFrequency = getMinDisplayFrequency();
|
||||
long maxFrequency = getMaxDisplayFrequency();
|
||||
|
||||
//Frequency increments for label and tick spacing
|
||||
int label = mLabelSizeMonitor.getLabelIncrement( graphics );
|
||||
int major = mLabelSizeMonitor.getMajorTickIncrement( graphics );
|
||||
int minor = mLabelSizeMonitor.getMinorTickIncrement( graphics );
|
||||
int label = mLabelSizeMonitor.getLabelIncrement( graphics );
|
||||
|
||||
long start = minFrequency - ( minFrequency % label );
|
||||
|
||||
long frequency = start;
|
||||
|
||||
//Adjust the start frequency to a multiple of the minor tick spacing
|
||||
long frequency = minFrequency - ( minFrequency % minor );
|
||||
|
||||
while( frequency < maxFrequency )
|
||||
{
|
||||
int offset = (int)( frequency - start );
|
||||
|
||||
if( offset % label == 0 )
|
||||
if( frequency % label == 0 )
|
||||
{
|
||||
drawFrequencyLineAndLabel( graphics, frequency );
|
||||
}
|
||||
else if( offset % major == 0 )
|
||||
else if( frequency % major == 0 )
|
||||
{
|
||||
drawTickLine( graphics, frequency, true );
|
||||
}
|
||||
@@ -328,6 +371,8 @@ public class OverlayPanel extends JPanel
|
||||
|
||||
frequency += minor;
|
||||
}
|
||||
|
||||
graphics.setStroke( currentStroke );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,7 +401,7 @@ public class OverlayPanel extends JPanel
|
||||
double xAxis = getAxisFromFrequency( frequency );
|
||||
|
||||
double start = getSize().getHeight() - mSpectrumInset;
|
||||
double end = start + ( major ? 6.0d : 3.0d );
|
||||
double end = start + ( major ? 9.0d : 3.0d );
|
||||
|
||||
graphics.draw( new Line2D.Double( xAxis, start, xAxis, end ) );
|
||||
}
|
||||
@@ -414,7 +459,8 @@ public class OverlayPanel extends JPanel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frequency corresponding to the x-axis value
|
||||
* Returns the frequency corresponding to the x-axis value using the current
|
||||
* zoom level.
|
||||
*/
|
||||
public long getFrequencyFromAxis( double xAxis )
|
||||
{
|
||||
@@ -422,7 +468,15 @@ public class OverlayPanel extends JPanel
|
||||
|
||||
double offset = xAxis / width;
|
||||
|
||||
return getMinFrequency() + Math.round( (double)mBandwidth * offset );
|
||||
long frequency = getMinDisplayFrequency() +
|
||||
Math.round( (double)getDisplayBandwidth() * offset );
|
||||
|
||||
if( frequency > ( getMaxFrequency() ) )
|
||||
{
|
||||
frequency = getMaxFrequency();
|
||||
}
|
||||
|
||||
return frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -432,16 +486,14 @@ public class OverlayPanel extends JPanel
|
||||
double xaxis,
|
||||
long frequency )
|
||||
{
|
||||
String label = mFrequencyFormat.format( (float)frequency / 1000000.0f );
|
||||
String label = mLabelSizeMonitor.format( frequency );
|
||||
|
||||
FontMetrics fontMetrics = graphics.getFontMetrics( this.getFont() );
|
||||
FontMetrics fontMetrics = graphics.getFontMetrics( this.getFont() );
|
||||
|
||||
Rectangle2D rect = fontMetrics.getStringBounds( label, graphics );
|
||||
|
||||
float xOffset = (float)rect.getWidth() / 2;
|
||||
|
||||
// graphics.drawString( label, (float)( xaxis - xOffset ),
|
||||
// (float)( getSize().getHeight() - ( mSpectrumInset * 0.2d ) ) );
|
||||
graphics.drawString( label, (float)( xaxis - xOffset ),
|
||||
(float)( getSize().getHeight() - 2.0f ) );
|
||||
}
|
||||
@@ -598,24 +650,15 @@ public class OverlayPanel extends JPanel
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event )
|
||||
{
|
||||
mLabelSizeMonitor.frequencyChanged( event );
|
||||
|
||||
switch( event.getAttribute() )
|
||||
{
|
||||
case SAMPLE_RATE:
|
||||
mBandwidth = event.getValue().intValue();
|
||||
|
||||
if( mBandwidth < 200000 )
|
||||
{
|
||||
mFrequencyFormat = new DecimalFormat( "0.00" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mFrequencyFormat = new DecimalFormat( "0.0" );
|
||||
}
|
||||
mLabelSizeMonitor.update();
|
||||
break;
|
||||
case FREQUENCY:
|
||||
mFrequency = event.getValue().longValue();
|
||||
mLabelSizeMonitor.update();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -750,186 +793,134 @@ public class OverlayPanel extends JPanel
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingDeleted( Setting setting )
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
public void settingDeleted( Setting setting ) { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Monitors the display for resize events so that we can calculate how many
|
||||
* frequency labels will fit within the current screen real estate
|
||||
* Calculates correct spacing and format for frequency labels and major/minor
|
||||
* tick lines based on current frequency, bandwidth, zoom and screen size.
|
||||
*/
|
||||
public class LabelSizeMonitor implements ComponentListener,
|
||||
FrequencyChangeListener
|
||||
public class LabelSizeManager implements ComponentListener
|
||||
{
|
||||
private static final int MAJOR_TICK_MINIMUM = 10000; //10 kHz
|
||||
private static final int MINOR_TICK_MINIMUM = 1000; //1 kHz
|
||||
private static final int TICK_SPACING_MINIMUM = 10; //pixels
|
||||
private static final double LABEL_FILL_THRESHOLD = 0.5d;
|
||||
|
||||
private boolean mUpdateRequired = true;
|
||||
private LabelDisplay mLabelDisplay = LabelDisplay.DIGIT_3;
|
||||
private int mMajorTickIncrement;
|
||||
private int mMinorTickIncrement;
|
||||
private int mLabelIncrement;
|
||||
private DecimalFormat mFrequencyFormat = new DecimalFormat( "0.0" );
|
||||
|
||||
private boolean mUpdateRequired = true;
|
||||
private int mLabelIncrement = 1;
|
||||
private int mMajorTickIncrement = 1;
|
||||
private int mMinorTickIncrement = 1;
|
||||
|
||||
public String format( long frequency )
|
||||
{
|
||||
return mFrequencyFormat.format( (double)frequency / 1E6D );
|
||||
}
|
||||
|
||||
private void setPrecision( int precision )
|
||||
{
|
||||
if( precision < 1 )
|
||||
{
|
||||
precision = 1;
|
||||
}
|
||||
|
||||
if( precision > 5 )
|
||||
{
|
||||
precision = 5;
|
||||
}
|
||||
|
||||
mFrequencyFormat.setMinimumFractionDigits( precision );
|
||||
mFrequencyFormat.setMaximumFractionDigits( precision );
|
||||
}
|
||||
|
||||
private void update( Graphics2D graphics )
|
||||
{
|
||||
if( mUpdateRequired )
|
||||
{
|
||||
double width = OverlayPanel.this.getSize().getWidth();
|
||||
|
||||
int major = MAJOR_TICK_MINIMUM;
|
||||
|
||||
while( width / ( (double)mBandwidth /
|
||||
(double)major ) < TICK_SPACING_MINIMUM )
|
||||
{
|
||||
major *= 10;
|
||||
}
|
||||
|
||||
mMajorTickIncrement = major;
|
||||
|
||||
int minor = MINOR_TICK_MINIMUM;
|
||||
|
||||
while( width / ( (double)mBandwidth /
|
||||
(double)minor ) < TICK_SPACING_MINIMUM )
|
||||
{
|
||||
minor *= 10;
|
||||
}
|
||||
|
||||
if( minor == major )
|
||||
{
|
||||
minor = (int)( major / 2 );
|
||||
}
|
||||
|
||||
mMinorTickIncrement = minor;
|
||||
//Set maximum precision as a starting point
|
||||
setPrecision( 5 );
|
||||
|
||||
FontMetrics fontMetrics =
|
||||
graphics.getFontMetrics( OverlayPanel.this.getFont() );
|
||||
|
||||
Rectangle2D labelDimension = fontMetrics.getStringBounds(
|
||||
mLabelDisplay.getExample(), graphics );
|
||||
|
||||
int maxLabelCount = (int)( width / labelDimension.getWidth() );
|
||||
int maxLabelWidth = fontMetrics.stringWidth( format( getMaxDisplayFrequency() ) );
|
||||
|
||||
double maxLabels = ( (double)OverlayPanel.this.getWidth() *
|
||||
LABEL_FILL_THRESHOLD ) /
|
||||
(double)maxLabelWidth;
|
||||
|
||||
//Calculate the next smallest base 10 value for the major increment
|
||||
int power = (int)Math.log10( (double)getDisplayBandwidth() / maxLabels );
|
||||
|
||||
//Set the number of decimal places to display in frequency labels
|
||||
int precision = 5 - power;
|
||||
|
||||
int label = major;
|
||||
int start = (int)Math.pow( 10.0, power + 1 );
|
||||
|
||||
while( ( (double)mBandwidth / (double)label ) > maxLabelCount )
|
||||
{
|
||||
label += major;
|
||||
}
|
||||
int minimum = (int)Math.pow( 10.0, power );
|
||||
|
||||
int labelIncrement = start;
|
||||
|
||||
while( ( (double)getDisplayBandwidth() /
|
||||
(double)labelIncrement ) < maxLabels &&
|
||||
labelIncrement >= minimum )
|
||||
{
|
||||
labelIncrement /= 2;
|
||||
precision++;
|
||||
}
|
||||
|
||||
mLabelIncrement = label;
|
||||
|
||||
mUpdateRequired = false;
|
||||
if( labelIncrement == minimum )
|
||||
{
|
||||
precision = 5 - power;
|
||||
}
|
||||
|
||||
setPrecision( precision );
|
||||
|
||||
mLabelIncrement = labelIncrement;
|
||||
mMajorTickIncrement = labelIncrement / 2;
|
||||
mMinorTickIncrement = labelIncrement / 10;
|
||||
|
||||
mUpdateRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the display to update the label and frequency display
|
||||
* calculations
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
mUpdateRequired = true;
|
||||
}
|
||||
|
||||
public int getMajorTickIncrement( Graphics2D graphics )
|
||||
{
|
||||
//Check to see if a calculation update is scheduled
|
||||
update( graphics );
|
||||
|
||||
return mMajorTickIncrement;
|
||||
}
|
||||
|
||||
|
||||
public int getMinorTickIncrement( Graphics2D graphics )
|
||||
{
|
||||
update( graphics );
|
||||
|
||||
return mMinorTickIncrement;
|
||||
}
|
||||
|
||||
public int getLabelIncrement( Graphics2D graphics )
|
||||
{
|
||||
update( graphics );
|
||||
|
||||
return mLabelIncrement;
|
||||
}
|
||||
|
||||
public LabelDisplay getLabelDisplay()
|
||||
{
|
||||
return mLabelDisplay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent arg0 )
|
||||
{
|
||||
mUpdateRequired = true;
|
||||
update();
|
||||
}
|
||||
|
||||
public void componentHidden( ComponentEvent arg0 ) {}
|
||||
public void componentMoved( ComponentEvent arg0 ) {}
|
||||
public void componentShown( ComponentEvent arg0 ) {}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event )
|
||||
{
|
||||
switch( event.getAttribute() )
|
||||
{
|
||||
case FREQUENCY:
|
||||
LabelDisplay display = LabelDisplay
|
||||
.fromFrequency( event.getValue().longValue() );
|
||||
|
||||
if( mLabelDisplay != display )
|
||||
{
|
||||
mLabelDisplay = display;
|
||||
mUpdateRequired = true;
|
||||
}
|
||||
break;
|
||||
case SAMPLE_RATE:
|
||||
mUpdateRequired = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency display formats for determining label sizing and value formatting
|
||||
*/
|
||||
public enum LabelDisplay
|
||||
{
|
||||
DIGIT_1( " 9.9 " ),
|
||||
DIGIT_2( " 99.9 " ),
|
||||
DIGIT_3( " 999.9 " ),
|
||||
DIGIT_4( " 9999.9 " ),
|
||||
DIGIT_5( " 99999.9 " );
|
||||
|
||||
private String mExample;
|
||||
|
||||
private LabelDisplay( String example )
|
||||
{
|
||||
mExample = example;
|
||||
}
|
||||
|
||||
public String getExample()
|
||||
{
|
||||
return mExample;
|
||||
}
|
||||
|
||||
public static LabelDisplay fromFrequency( long frequency )
|
||||
{
|
||||
if( frequency < 10000000l ) //10 MHz
|
||||
{
|
||||
return LabelDisplay.DIGIT_1;
|
||||
}
|
||||
else if( frequency < 100000000l ) //100 MHz
|
||||
{
|
||||
return LabelDisplay.DIGIT_2;
|
||||
}
|
||||
else if( frequency < 1000000000l ) //1,000 MHz
|
||||
{
|
||||
return LabelDisplay.DIGIT_3;
|
||||
}
|
||||
else if( frequency < 10000000000l ) //10,000 MHz
|
||||
{
|
||||
return LabelDisplay.DIGIT_4;
|
||||
}
|
||||
|
||||
return LabelDisplay.DIGIT_5;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChannelDisplay
|
||||
{
|
||||
ALL, ENABLED, NONE;
|
||||
|
||||
@@ -25,10 +25,7 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
@@ -48,6 +45,7 @@ import javax.swing.JSplitPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
|
||||
import module.decode.DecoderType;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
@@ -55,13 +53,12 @@ import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import playlist.PlaylistManager;
|
||||
import sample.Listener;
|
||||
import sample.SampleType;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.ColorSettingMenuItem;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import settings.SettingsManager;
|
||||
import source.SourceException;
|
||||
import source.tuner.Tuner;
|
||||
@@ -81,28 +78,17 @@ import spectrum.menu.SmoothingTypeItem;
|
||||
|
||||
import com.jidesoft.swing.JideSplitPane;
|
||||
|
||||
import controller.ResourceManager;
|
||||
import controller.ConfigurationControllerModel;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.ChannelEvent;
|
||||
import controller.channel.ChannelEventListener;
|
||||
import controller.channel.ChannelManager;
|
||||
import controller.channel.ChannelUtils;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.smoothing.SmoothingFilter.SmoothingType;
|
||||
|
||||
/**
|
||||
* Spectral Display Panel - comprises a DFTProcessor coupled with a waterfall
|
||||
* display and a spectrum display, with an overlay of frequency data and channel
|
||||
* data.
|
||||
*
|
||||
* Processes float or complex sample data and displays the frequency content
|
||||
* in the spectral and waterfall displays.
|
||||
*/
|
||||
public class SpectralDisplayPanel extends JPanel
|
||||
implements ChannelEventListener,
|
||||
Listener<ComplexBuffer>,
|
||||
implements Listener<ComplexBuffer>,
|
||||
FrequencyChangeListener,
|
||||
IDFTWidthChangeProcessor,
|
||||
SettingChangeListener,
|
||||
TunerSelectionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -110,10 +96,10 @@ public class SpectralDisplayPanel extends JPanel
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( SpectralDisplayPanel.class );
|
||||
|
||||
private static DecimalFormat sCURSOR_FORMAT = new DecimalFormat( "000.00000" );
|
||||
|
||||
public static final int NO_ZOOM = 0;
|
||||
public static final int MAX_ZOOM = 6;
|
||||
|
||||
private static DecimalFormat sCURSOR_FORMAT = new DecimalFormat( "000.00000" );
|
||||
|
||||
private DFTSize mDFTSize = DFTSize.FFT04096;
|
||||
private int mZoom = 0;
|
||||
@@ -126,13 +112,42 @@ public class SpectralDisplayPanel extends JPanel
|
||||
private OverlayPanel mOverlayPanel;
|
||||
private DFTProcessor mDFTProcessor;
|
||||
private DFTResultsConverter mDFTConverter;
|
||||
private ResourceManager mResourceManager;
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private SettingsManager mSettingsManager;
|
||||
private ConfigurationControllerModel mController;
|
||||
private Tuner mTuner;
|
||||
|
||||
public SpectralDisplayPanel( ResourceManager resourceManager )
|
||||
/**
|
||||
* Spectral Display Panel provides a frequency component display with a
|
||||
* historical waterfall display and a transparent overlay to show frequency,
|
||||
* cursor and channel information.
|
||||
*
|
||||
* Mouse scrolling and zooming are supported and the waterfall display can
|
||||
* be paused.
|
||||
*
|
||||
* Complex sample buffers are processed by a DFTProcessor and the output of
|
||||
* the DFT is translated to decibels for display in the spectrum and
|
||||
* waterfall components.
|
||||
*/
|
||||
public SpectralDisplayPanel( ChannelManager channelManager,
|
||||
ConfigurationControllerModel controller,
|
||||
PlaylistManager playlistManager,
|
||||
SettingsManager settingsManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
mController = controller;
|
||||
mPlaylistManager = playlistManager;
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
mSpectrumPanel = new SpectrumPanel( mSettingsManager );
|
||||
mOverlayPanel = new OverlayPanel( mSettingsManager, channelManager );
|
||||
mWaterfallPanel = new WaterfallPanel( mSettingsManager );
|
||||
|
||||
//Register to receive tuner selection events
|
||||
if( mController != null )
|
||||
{
|
||||
mController.addListener( (TunerSelectionListener)this );
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -140,8 +155,15 @@ public class SpectralDisplayPanel extends JPanel
|
||||
{
|
||||
/* De-register from receiving samples when the window closes */
|
||||
clearTuner();
|
||||
|
||||
mResourceManager.getChannelManager().removeListener( this );
|
||||
|
||||
if( mController != null )
|
||||
{
|
||||
mController.removeListener( (TunerSelectionListener)this );
|
||||
}
|
||||
|
||||
mController = null;
|
||||
mPlaylistManager = null;
|
||||
mSettingsManager = null;
|
||||
|
||||
mDFTProcessor.dispose();
|
||||
mDFTProcessor = null;
|
||||
@@ -158,7 +180,6 @@ public class SpectralDisplayPanel extends JPanel
|
||||
mOverlayPanel.dispose();
|
||||
mOverlayPanel = null;
|
||||
|
||||
mResourceManager = null;
|
||||
|
||||
mTuner = null;
|
||||
}
|
||||
@@ -188,7 +209,7 @@ public class SpectralDisplayPanel extends JPanel
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current zoom level (2^zoom)
|
||||
* Sets the current zoom level which will be 2 to the power of zoom (2^zoom)
|
||||
*
|
||||
* 0 No Zoom
|
||||
* 1 2x Zoom
|
||||
@@ -198,31 +219,82 @@ public class SpectralDisplayPanel extends JPanel
|
||||
* 5 32x Zoom
|
||||
* 6 64x Zoom
|
||||
*
|
||||
* @param zoom level, 0 - 5.
|
||||
* @param zoom level, 0 - 6.
|
||||
* @param frequency under the mouse to maintain while zooming
|
||||
* @param xAxisOffset where to maintain the frequency under the mouse
|
||||
*/
|
||||
public void setZoom( int zoom, long frequency, double windowOffset )
|
||||
{
|
||||
if( zoom < NO_ZOOM )
|
||||
{
|
||||
zoom = NO_ZOOM;
|
||||
}
|
||||
else if( zoom > MAX_ZOOM )
|
||||
{
|
||||
zoom = MAX_ZOOM;
|
||||
}
|
||||
|
||||
if( zoom != mZoom )
|
||||
{
|
||||
mZoom = zoom;
|
||||
|
||||
double zoomTotal = Math.pow( 2.0, mZoom );
|
||||
//Calculate the bin offset that would place the reference frequency
|
||||
//at the left edge of the zoom window.
|
||||
double binOffsetToFrequency = getBinOffset( frequency );
|
||||
|
||||
double overallOffset = getBinOffset( frequency );
|
||||
double windowBinOffset = ( (double)mDFTSize.getSize() /
|
||||
(double)zoomTotal ) *
|
||||
windowOffset;
|
||||
//Calculate the bin offset into the newly sized zoom window that
|
||||
//would place the frequency in the same proportional window location
|
||||
//that it was in the previous zoom size
|
||||
double windowBinOffset = (double)getZoomWindowSizeInBins() * windowOffset;
|
||||
|
||||
//Set the overall offset to place the reference frequency in the
|
||||
//same location in the newly zoomed window
|
||||
double offset = binOffsetToFrequency - windowBinOffset;
|
||||
|
||||
mDFTZoomWindowOffset = (int)( overallOffset - windowBinOffset );
|
||||
mSpectrumPanel.setZoom( mZoom );
|
||||
mOverlayPanel.setZoom( mZoom );
|
||||
mWaterfallPanel.setZoom( mZoom );
|
||||
|
||||
mSpectrumPanel.setZoom( mZoom, mDFTZoomWindowOffset );
|
||||
mOverlayPanel.setZoom( mZoom, mDFTZoomWindowOffset );
|
||||
mWaterfallPanel.setZoom( mZoom, mDFTZoomWindowOffset );
|
||||
setZoomWindowOffset( offset );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset (in DFT bins) to the first bin that the zoom window displays
|
||||
*/
|
||||
public void setZoomWindowOffset( double offset )
|
||||
{
|
||||
if( offset < 0 )
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if( offset > ( mDFTSize.getSize() - getZoomWindowSizeInBins() ) )
|
||||
{
|
||||
offset = mDFTSize.getSize() - getZoomWindowSizeInBins();
|
||||
}
|
||||
|
||||
mDFTZoomWindowOffset = (int)offset;
|
||||
|
||||
mSpectrumPanel.setZoomWindowOffset( mDFTZoomWindowOffset );
|
||||
mOverlayPanel.setZoomWindowOffset( mDFTZoomWindowOffset );
|
||||
mWaterfallPanel.setZoomWindowOffset( mDFTZoomWindowOffset );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the size of the current zoom window in DFT bins
|
||||
*/
|
||||
private int getZoomWindowSizeInBins()
|
||||
{
|
||||
return mDFTSize.getSize() / getZoomMultiplier();
|
||||
}
|
||||
|
||||
|
||||
public int getZoomMultiplier()
|
||||
{
|
||||
return (int)Math.pow( 2.0, mZoom );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the overall offset of the frequency from the current minimum
|
||||
* frequency in terms of total FFT width
|
||||
@@ -231,39 +303,18 @@ public class SpectralDisplayPanel extends JPanel
|
||||
*/
|
||||
private double getBinOffset( long frequency )
|
||||
{
|
||||
double offset = 0.0;
|
||||
|
||||
if( mOverlayPanel.containsFrequency( frequency ) )
|
||||
{
|
||||
return (double)mDFTSize.getSize() *
|
||||
offset = (double)mDFTSize.getSize() *
|
||||
( (double)( frequency - mOverlayPanel.getMinFrequency() ) /
|
||||
(double)mOverlayPanel.getBandwidth() );
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors for setting changes. Colors can be changed by external actions
|
||||
* and will automatically update in this class
|
||||
*/
|
||||
@Override
|
||||
public void settingChanged( Setting setting )
|
||||
{
|
||||
if( mOverlayPanel != null )
|
||||
{
|
||||
mOverlayPanel.settingChanged( setting );
|
||||
}
|
||||
|
||||
if( mWaterfallPanel != null )
|
||||
{
|
||||
mWaterfallPanel.settingChanged( setting );
|
||||
}
|
||||
|
||||
if( mSpectrumPanel != null )
|
||||
{
|
||||
mSpectrumPanel.settingChanged( setting );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides JComponent method to return false, since we have overlapping
|
||||
* panels with the spectrum and channel panels
|
||||
@@ -277,9 +328,6 @@ public class SpectralDisplayPanel extends JPanel
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow]", "[grow]") );
|
||||
|
||||
//Register for any future settings (ie color) changes
|
||||
mResourceManager.getSettingsManager().addListener( this );
|
||||
|
||||
/**
|
||||
* The layered pane holds the overlapping spectrum and channel panels
|
||||
* and manages the sizing of each panel with the resize listener
|
||||
@@ -293,11 +341,6 @@ public class SpectralDisplayPanel extends JPanel
|
||||
*/
|
||||
MouseEventProcessor mouser = new MouseEventProcessor();
|
||||
|
||||
//Create the spectrum panel
|
||||
mSpectrumPanel = new SpectrumPanel( mResourceManager );
|
||||
|
||||
//Create the overlay panel
|
||||
mOverlayPanel = new OverlayPanel( mResourceManager );
|
||||
mOverlayPanel.addMouseListener( mouser );
|
||||
mOverlayPanel.addMouseMotionListener( mouser );
|
||||
mOverlayPanel.addMouseWheelListener( mouser );
|
||||
@@ -307,7 +350,6 @@ public class SpectralDisplayPanel extends JPanel
|
||||
mLayeredPanel.add( mOverlayPanel, new Integer( 1 ), 0 );
|
||||
|
||||
//Create the waterfall
|
||||
mWaterfallPanel = new WaterfallPanel( mResourceManager );
|
||||
mWaterfallPanel.addMouseListener( mouser );
|
||||
mWaterfallPanel.addMouseMotionListener( mouser );
|
||||
mWaterfallPanel.addMouseWheelListener( mouser );
|
||||
@@ -355,22 +397,17 @@ public class SpectralDisplayPanel extends JPanel
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel change events
|
||||
* Complex sample buffer receive method
|
||||
*/
|
||||
@Override
|
||||
public void channelChanged( ChannelEvent event )
|
||||
{
|
||||
mOverlayPanel.channelChanged( event );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( ComplexBuffer sampleBuffer )
|
||||
{
|
||||
mDFTProcessor.receive( sampleBuffer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tuner selected events
|
||||
* Responds to tuner selection event by deregistering from the current
|
||||
* complex sample buffer source and registering with the tuner argument.
|
||||
*/
|
||||
@Override
|
||||
public void tunerSelected( Tuner tuner )
|
||||
@@ -391,8 +428,8 @@ public class SpectralDisplayPanel extends JPanel
|
||||
|
||||
mSpectrumPanel.setSampleSize( mTuner.getSampleSize() );
|
||||
|
||||
//Fire frequency and sample rate change events so that everyone
|
||||
//can init
|
||||
//Fire frequency and sample rate change events so that the spectrum
|
||||
//and overlay panels can synchronize
|
||||
try
|
||||
{
|
||||
frequencyChanged( new FrequencyChangeEvent(
|
||||
@@ -449,26 +486,23 @@ public class SpectralDisplayPanel extends JPanel
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouse event handler for the channel panel.
|
||||
* Mouse event handler for the spectral display panel.
|
||||
*/
|
||||
public class MouseEventProcessor implements MouseMotionListener,
|
||||
MouseListener,
|
||||
MouseWheelListener
|
||||
public class MouseEventProcessor extends MouseInputAdapter
|
||||
{
|
||||
private int mDFTZoomWindowOffsetAtDragStart = 0;
|
||||
private int mDragStartX = 0;
|
||||
private double mPixelsPerBin;
|
||||
|
||||
public MouseEventProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved( MouseWheelEvent e )
|
||||
{
|
||||
int zoom = mZoom - e.getWheelRotation();
|
||||
|
||||
if( zoom < NO_ZOOM )
|
||||
{
|
||||
zoom = NO_ZOOM;
|
||||
}
|
||||
else if( zoom > MAX_ZOOM )
|
||||
{
|
||||
zoom = MAX_ZOOM;
|
||||
}
|
||||
|
||||
long frequency = mOverlayPanel.getFrequencyFromAxis( e.getX() );
|
||||
|
||||
double windowOffset = (double)e.getX() / (double)getWidth();
|
||||
@@ -481,12 +515,47 @@ public class SpectralDisplayPanel extends JPanel
|
||||
{
|
||||
update( event );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent event )
|
||||
{
|
||||
{
|
||||
update( event );
|
||||
|
||||
int dragDistance = mDragStartX - event.getX();
|
||||
|
||||
double binDistance = (double)dragDistance / mPixelsPerBin;
|
||||
|
||||
int offset = (int)( mDFTZoomWindowOffsetAtDragStart + binDistance );
|
||||
|
||||
if( offset < 0 )
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
int maxOffset = mDFTSize.getSize() - ( mDFTSize.getSize() / getZoomMultiplier() );
|
||||
|
||||
if( offset > maxOffset )
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
|
||||
setZoomWindowOffset( offset );
|
||||
}
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e )
|
||||
{
|
||||
mDragStartX = e.getX();
|
||||
|
||||
mDFTZoomWindowOffsetAtDragStart = mDFTZoomWindowOffset;
|
||||
|
||||
mPixelsPerBin = (double)getWidth() /
|
||||
( (double)( mDFTSize.getSize() ) /
|
||||
(double)getZoomMultiplier() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cursor display while the mouse is performing actions
|
||||
*/
|
||||
private void update( MouseEvent event )
|
||||
{
|
||||
if( event.getComponent() == mOverlayPanel )
|
||||
@@ -547,8 +616,7 @@ public class SpectralDisplayPanel extends JPanel
|
||||
for( Channel channel: channels )
|
||||
{
|
||||
JMenu channelMenu = ChannelUtils.getContextMenu(
|
||||
mResourceManager.getPlaylistManager(),
|
||||
channel, SpectralDisplayPanel.this );
|
||||
mPlaylistManager, channel, SpectralDisplayPanel.this );
|
||||
|
||||
if( channelMenu != null )
|
||||
{
|
||||
@@ -570,7 +638,7 @@ public class SpectralDisplayPanel extends JPanel
|
||||
|
||||
for( DecoderType type: DecoderType.getPrimaryDecoders() )
|
||||
{
|
||||
decoderMenu.add( new DecoderItem( mResourceManager,
|
||||
decoderMenu.add( new DecoderItem( mController,
|
||||
frequency,
|
||||
type ) );
|
||||
|
||||
@@ -587,30 +655,28 @@ public class SpectralDisplayPanel extends JPanel
|
||||
*/
|
||||
JMenu colorMenu = new JMenu( "Color" );
|
||||
|
||||
SettingsManager sm = mResourceManager.getSettingsManager();
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_CONFIG ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_CONFIG_PROCESSING ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_CONFIG_SELECTED ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_CURSOR ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_LINE ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_BACKGROUND ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_GRADIENT_BOTTOM ) );
|
||||
|
||||
colorMenu.add( new ColorSettingMenuItem( sm,
|
||||
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_GRADIENT_TOP ) );
|
||||
|
||||
contextMenu.add( colorMenu );
|
||||
@@ -734,11 +800,6 @@ public class SpectralDisplayPanel extends JPanel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {}
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {}
|
||||
}
|
||||
|
||||
public class PauseItem extends JCheckBoxMenuItem
|
||||
@@ -859,15 +920,17 @@ public class SpectralDisplayPanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
private ConfigurationControllerModel mController;
|
||||
private long mFrequency;
|
||||
private DecoderType mDecoder;
|
||||
|
||||
public DecoderItem( ResourceManager manager, long frequency, DecoderType type )
|
||||
public DecoderItem( ConfigurationControllerModel controller,
|
||||
long frequency,
|
||||
DecoderType type )
|
||||
{
|
||||
super( type.getDisplayString() );
|
||||
|
||||
mResourceManager = manager;
|
||||
mController = controller;
|
||||
mFrequency = frequency;
|
||||
mDecoder = type;
|
||||
|
||||
@@ -876,13 +939,9 @@ public class SpectralDisplayPanel extends JPanel
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
mResourceManager.getController()
|
||||
.createChannel( mFrequency, mDecoder );
|
||||
mController.createChannel( mFrequency, mDecoder );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingDeleted( Setting setting ) {}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,13 @@ import java.awt.event.WindowListener;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import playlist.PlaylistManager;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import settings.SettingsManager;
|
||||
import source.tuner.Tuner;
|
||||
import controller.ConfigurationControllerModel;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.ChannelManager;
|
||||
|
||||
public class SpectrumFrame extends JFrame implements WindowListener
|
||||
{
|
||||
@@ -34,23 +38,24 @@ public class SpectrumFrame extends JFrame implements WindowListener
|
||||
private ResourceManager mResourceManager;
|
||||
private SpectralDisplayPanel mSpectralDisplayPanel;
|
||||
|
||||
public SpectrumFrame( ResourceManager resourceManager, Tuner tuner )
|
||||
public SpectrumFrame( ChannelManager channelManager,
|
||||
ConfigurationControllerModel controller,
|
||||
PlaylistManager playlistManager,
|
||||
SettingsManager settingsManager,
|
||||
Tuner tuner )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
setTitle( "SDRTRunk [" + tuner.getName() + "]" );
|
||||
setBounds( 100, 100, 1280, 600 );
|
||||
setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
||||
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow]", "[grow]") );
|
||||
|
||||
mSpectralDisplayPanel = new SpectralDisplayPanel( resourceManager );
|
||||
mSpectralDisplayPanel = new SpectralDisplayPanel( channelManager,
|
||||
controller, playlistManager, settingsManager );
|
||||
|
||||
mSpectralDisplayPanel.tunerSelected( tuner );
|
||||
add( mSpectralDisplayPanel, "grow" );
|
||||
|
||||
/* Register spectral display on channel manager to get channel updates */
|
||||
mResourceManager.getChannelManager().addListener( mSpectralDisplayPanel );
|
||||
|
||||
/* Register a shutdown listener */
|
||||
this.addWindowListener( this );
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import settings.ColorSetting;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import controller.ResourceManager;
|
||||
import settings.SettingsManager;
|
||||
import dsp.filter.smoothing.GaussianSmoothingFilter;
|
||||
import dsp.filter.smoothing.NoSmoothingFilter;
|
||||
import dsp.filter.smoothing.RectangularSmoothingFilter;
|
||||
@@ -59,11 +59,11 @@ public class SpectrumPanel extends JPanel
|
||||
new RenderingHints( RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON );
|
||||
|
||||
//Color settings
|
||||
private static final String SPECTRUM_BACKGROUND = "spectrum_background";
|
||||
private static final String SPECTRUM_GRADIENT_TOP = "spectrum_gradient_top";
|
||||
private static final String SPECTRUM_GRADIENT_BOTTOM = "spectrum_gradient_bottom";
|
||||
private static final String SPECTRUM_LINE = "spectrum_line";
|
||||
static
|
||||
{
|
||||
RENDERING_HINTS.put( RenderingHints.KEY_RENDERING,
|
||||
RenderingHints.VALUE_RENDER_QUALITY );
|
||||
}
|
||||
|
||||
private Color mColorSpectrumBackground;
|
||||
private Color mColorSpectrumGradientTop;
|
||||
@@ -86,29 +86,36 @@ public class SpectrumPanel extends JPanel
|
||||
private float mDBScale;
|
||||
|
||||
private int mZoom = 0;
|
||||
private int mZoomBinOffset = 0;;
|
||||
private int mZoomWindowOffset = 0;;
|
||||
|
||||
private SettingsManager mSettingsManager;
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
|
||||
public SpectrumPanel( ResourceManager resourceManager )
|
||||
public SpectrumPanel( SettingsManager settingsManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
RENDERING_HINTS.put( RenderingHints.KEY_RENDERING,
|
||||
RenderingHints.VALUE_RENDER_QUALITY );
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.addListener( this );
|
||||
}
|
||||
|
||||
setSampleSize( 16.0 );
|
||||
|
||||
mSmoothingFilter.setPointSize( SmoothingFilter.SMOOTHING_DEFAULT );
|
||||
|
||||
getSettings();
|
||||
getColors();
|
||||
|
||||
setAveraging( mAveraging );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mResourceManager = null;
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.removeListener( this );
|
||||
}
|
||||
|
||||
mSettingsManager = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +148,8 @@ public class SpectrumPanel extends JPanel
|
||||
|
||||
for( int x = 0; x < mDisplayFFTBins.length; x++ )
|
||||
{
|
||||
mDisplayFFTBins[ x ] += ( smoothedBins[ x ] - mDisplayFFTBins[ x ] ) * gain;
|
||||
mDisplayFFTBins[ x ] +=
|
||||
( smoothedBins[ x ] - mDisplayFFTBins[ x ] ) * gain;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -158,8 +166,8 @@ public class SpectrumPanel extends JPanel
|
||||
super.paintComponent( g );
|
||||
|
||||
Graphics2D graphics = (Graphics2D) g;
|
||||
graphics.setBackground( mColorSpectrumBackground );
|
||||
|
||||
graphics.setBackground( mColorSpectrumBackground );
|
||||
|
||||
graphics.setRenderingHints( RENDERING_HINTS );
|
||||
|
||||
@@ -272,13 +280,11 @@ public class SpectrumPanel extends JPanel
|
||||
*
|
||||
* @param zoom level, 0 - 5.
|
||||
*/
|
||||
public void setZoom( int zoom, int offset )
|
||||
public void setZoom( int zoom )
|
||||
{
|
||||
assert( 0 <= zoom && zoom <= 5 );
|
||||
|
||||
mZoom = zoom;
|
||||
|
||||
setZoomBinOffset( offset );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,9 +292,9 @@ public class SpectrumPanel extends JPanel
|
||||
*
|
||||
* @param offset
|
||||
*/
|
||||
public void setZoomBinOffset( int offset )
|
||||
public void setZoomWindowOffset( int offset )
|
||||
{
|
||||
mZoomBinOffset = offset;
|
||||
mZoomWindowOffset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,7 +336,7 @@ public class SpectrumPanel extends JPanel
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void getSettings()
|
||||
private void getColors()
|
||||
{
|
||||
mColorSpectrumBackground =
|
||||
getColor( ColorSettingName.SPECTRUM_BACKGROUND );
|
||||
@@ -349,8 +355,7 @@ public class SpectrumPanel extends JPanel
|
||||
*/
|
||||
private Color getColor( ColorSettingName name )
|
||||
{
|
||||
ColorSetting setting =
|
||||
mResourceManager.getSettingsManager().getColorSetting( name );
|
||||
ColorSetting setting = mSettingsManager.getColorSetting( name );
|
||||
|
||||
return setting.getColor();
|
||||
}
|
||||
@@ -385,6 +390,15 @@ public class SpectrumPanel extends JPanel
|
||||
}
|
||||
}
|
||||
|
||||
private int getZoomMultiplier()
|
||||
{
|
||||
return (int)Math.pow( 2.0, mZoom );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DFT result bins, or a zoomed and offset version of the bins
|
||||
* when the display is zoomed.
|
||||
*/
|
||||
private float[] getBins()
|
||||
{
|
||||
if( mZoom == 0 )
|
||||
@@ -393,16 +407,19 @@ public class SpectrumPanel extends JPanel
|
||||
}
|
||||
else
|
||||
{
|
||||
int zoom = (int)Math.pow( 2.0, mZoom );
|
||||
int length = mDisplayFFTBins.length / getZoomMultiplier();
|
||||
|
||||
int length = mDisplayFFTBins.length / zoom;
|
||||
int offset = mZoomWindowOffset;
|
||||
|
||||
int offset = mZoomBinOffset;
|
||||
|
||||
if( ( offset + length ) > mDisplayFFTBins.length )
|
||||
if( ( offset + length ) >= mDisplayFFTBins.length )
|
||||
{
|
||||
offset = mDisplayFFTBins.length - length;
|
||||
}
|
||||
|
||||
if( offset < 0 )
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
return Arrays.copyOfRange( mDisplayFFTBins, offset, offset + length );
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -40,26 +40,22 @@ import settings.ColorSetting;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import controller.ResourceManager;
|
||||
import settings.SettingsManager;
|
||||
|
||||
/**
|
||||
* Produces a JPanel filled with a waterfall image derived from a continuous
|
||||
* stream of received Discrete Fourier Transform (DFT) results from the
|
||||
* DFTProcessor class.
|
||||
*/
|
||||
public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
Pausable,
|
||||
SettingChangeListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( WaterfallPanel.class );
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static DecimalFormat CURSOR_FORMAT = new DecimalFormat( "0.00000" );
|
||||
private static final String SPECTRUM_CURSOR = "spectrum_cursor";
|
||||
private static final String PAUSED = "PAUSED";
|
||||
|
||||
private byte[] mPixels;
|
||||
private byte[] mPausedPixels;
|
||||
private int mDFTSize = 4096;
|
||||
private int mImageHeight = 700;
|
||||
private MemoryImageSource mMemoryImageSource;
|
||||
@@ -70,29 +66,50 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
private Point mCursorLocation = new Point( 0, 0 );
|
||||
private boolean mCursorVisible = false;
|
||||
private long mCursorFrequency = 0;
|
||||
private AtomicBoolean mPaused = new AtomicBoolean();
|
||||
private boolean mPaused = false;
|
||||
private int mZoom = 0;
|
||||
private int mDFTZoomOffset = 0;
|
||||
private int mDFTZoomWindowOffset = 0;
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
|
||||
public WaterfallPanel( ResourceManager resourceManager )
|
||||
private SettingsManager mSettingsManager;
|
||||
|
||||
/**
|
||||
* Displays a scrolling window of multiple DFT frequency bin outputs over
|
||||
* time. Maps DFT frequency bin decibel values into a 256 bucket color map
|
||||
* for display.
|
||||
*
|
||||
* @param settingsManager
|
||||
*/
|
||||
public WaterfallPanel( SettingsManager settingsManager )
|
||||
{
|
||||
super();
|
||||
|
||||
mResourceManager = resourceManager;
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
mSettingsManager.addListener( this );
|
||||
|
||||
mColorSpectrumCursor = getColor( ColorSettingName.SPECTRUM_CURSOR );
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepares this instance for disposal
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
mResourceManager = null;
|
||||
if( mSettingsManager != null )
|
||||
{
|
||||
mSettingsManager.removeListener( this );
|
||||
}
|
||||
|
||||
mSettingsManager = null;
|
||||
mMemoryImageSource = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resets the memory image source and byte backing array when the DFT point
|
||||
* size has changed
|
||||
*/
|
||||
private void reset()
|
||||
{
|
||||
mPixels = new byte[ mDFTSize * mImageHeight ];
|
||||
@@ -110,18 +127,27 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
}
|
||||
|
||||
/**
|
||||
* Pausable interface - pauses updates to the screen
|
||||
* Pausable interface - pauses updates to the waterfall
|
||||
*/
|
||||
public void setPaused( boolean paused )
|
||||
{
|
||||
mPaused.set( paused );
|
||||
if( paused )
|
||||
{
|
||||
mPausedPixels = mPixels.clone();
|
||||
}
|
||||
|
||||
mPaused = paused;
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current pause state
|
||||
* @return true if paused, false otherwise
|
||||
*/
|
||||
public boolean isPaused()
|
||||
{
|
||||
return mPaused.get();
|
||||
return mPaused;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,14 +159,31 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
* 3 8x Zoom
|
||||
* 4 16x Zoom
|
||||
* 5 32x Zoom
|
||||
* 6 64x Zoom
|
||||
*
|
||||
* @param zoom level, 0 - 5.
|
||||
* @param zoom level, 0 - 6.
|
||||
* @param offset into the DFT bins for display
|
||||
*/
|
||||
public void setZoom( int zoom, int offset )
|
||||
public void setZoom( int zoom )
|
||||
{
|
||||
mZoom = zoom;
|
||||
mDFTZoomOffset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplier for the current zoom level
|
||||
*/
|
||||
private int getZoomMultiplier()
|
||||
{
|
||||
return (int)Math.pow( 2.0, mZoom );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the zoom window offset from zero
|
||||
* @param offset in DFT bins
|
||||
*/
|
||||
public void setZoomWindowOffset( int offset )
|
||||
{
|
||||
mDFTZoomWindowOffset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,8 +192,7 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
*/
|
||||
private Color getColor( ColorSettingName name )
|
||||
{
|
||||
ColorSetting setting = mResourceManager.getSettingsManager()
|
||||
.getColorSetting( name );
|
||||
ColorSetting setting = mSettingsManager.getColorSetting( name );
|
||||
|
||||
return setting.getColor();
|
||||
}
|
||||
@@ -174,18 +216,37 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingDeleted( Setting setting ) { /* Not implemented */ }
|
||||
|
||||
/**
|
||||
* Sets the display location of the cursor. Cursor location monitoring is
|
||||
* handled external to this class.
|
||||
*
|
||||
* @param point
|
||||
*/
|
||||
public void setCursorLocation( Point point )
|
||||
{
|
||||
mCursorLocation = point;
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the current cursor display frequency. Cursor location frequency
|
||||
* monitoring is handled external to this class.
|
||||
*
|
||||
* @param frequency
|
||||
*/
|
||||
public void setCursorFrequency( long frequency )
|
||||
{
|
||||
mCursorFrequency = frequency;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Toggles the visibility of the cursor
|
||||
* @param visible
|
||||
*/
|
||||
public void setCursorVisible( boolean visible )
|
||||
{
|
||||
mCursorVisible = visible;
|
||||
@@ -193,21 +254,34 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the x-axis pixel offset from zero where to start rendering the
|
||||
* waterfall image
|
||||
*
|
||||
* @param multiplier - current zoom multiplier
|
||||
* @return x-axis pixel offset
|
||||
*/
|
||||
private int getPixelOffset( int multiplier )
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
if( mZoom != 0 )
|
||||
{
|
||||
return -(int)( (double)getWidth() * multiplier /
|
||||
(double)mDFTSize *
|
||||
(double)( mDFTZoomOffset ) );
|
||||
int zoomWidth = getWidth() * multiplier;
|
||||
|
||||
offset = -(int)( (double)zoomWidth / (double)mDFTSize *
|
||||
(double)( mDFTZoomWindowOffset ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the screen at each refresh
|
||||
*/
|
||||
public void paintComponent( Graphics g )
|
||||
{
|
||||
int multiplier = (int)Math.pow( 2.0, mZoom );
|
||||
int multiplier = getZoomMultiplier();
|
||||
|
||||
int offset = getPixelOffset( multiplier );
|
||||
|
||||
@@ -220,10 +294,11 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
|
||||
Graphics2D graphics = (Graphics2D) g;
|
||||
|
||||
graphics.setColor( mColorSpectrumCursor );
|
||||
|
||||
if( mCursorVisible )
|
||||
{
|
||||
|
||||
graphics.setColor( mColorSpectrumCursor );
|
||||
|
||||
graphics.draw( new Line2D.Float( mCursorLocation.x,
|
||||
0,
|
||||
@@ -235,22 +310,57 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
graphics.drawString( frequency ,
|
||||
mCursorLocation.x + 5,
|
||||
mCursorLocation.y );
|
||||
|
||||
if( mZoom != 0 )
|
||||
{
|
||||
graphics.drawString( "Zoom: " + (int)Math.pow( 2.0, mZoom ) + "x",
|
||||
mCursorLocation.x + 17, mCursorLocation.y + 11 );
|
||||
}
|
||||
}
|
||||
|
||||
if( mPaused.get() )
|
||||
if( mPaused )
|
||||
{
|
||||
graphics.drawString( PAUSED, 20, 20 );
|
||||
}
|
||||
|
||||
paintZoomIndicator( graphics );
|
||||
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* When zoom level is greater than zero, paints a small indicator at the
|
||||
* bottom center of the screen showing the location of the zoom window
|
||||
* within the overall DFT results window
|
||||
*/
|
||||
private void paintZoomIndicator( Graphics2D graphics )
|
||||
{
|
||||
if( mZoom != 0 )
|
||||
{
|
||||
int width = getWidth() / 4;
|
||||
|
||||
int x = ( getWidth() / 2 ) - ( width / 2 );
|
||||
|
||||
//Draw the outer window
|
||||
graphics.drawRect( x, getHeight() - 12, width, 10 );
|
||||
|
||||
int zoomWidth = width / getZoomMultiplier();
|
||||
|
||||
int windowOffset = 0;
|
||||
|
||||
if( mDFTZoomWindowOffset != 0 )
|
||||
{
|
||||
windowOffset = (int)( ( (double)mDFTZoomWindowOffset /
|
||||
(double)mDFTSize ) * width );
|
||||
}
|
||||
|
||||
//Draw the zoom window
|
||||
graphics.fillRect( x + windowOffset, getHeight() - 12, zoomWidth, 10 );
|
||||
|
||||
//Draw the zoom text
|
||||
graphics.drawString( "Zoom: " + getZoomMultiplier() + "x",
|
||||
x + width + 3, getHeight() - 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the DFT results listener interface method. This is the
|
||||
* primary method for receiving new frequency bin results.
|
||||
*/
|
||||
@Override
|
||||
public void receive( float[] update )
|
||||
{
|
||||
@@ -297,37 +407,25 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||
mPixels[ x ] = (byte)value;
|
||||
}
|
||||
}
|
||||
|
||||
if( !mPaused.get() )
|
||||
|
||||
//Task the swing event thread to update the display
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if( mMemoryImageSource != null )
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if( mMemoryImageSource != null )
|
||||
{
|
||||
if( mPaused )
|
||||
{
|
||||
mMemoryImageSource.newPixels( mPausedPixels, mColorModel, 0, mDFTSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
mMemoryImageSource.newPixels( mPixels, mColorModel, 0, mDFTSize );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public class Handler implements MouseListener
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e )
|
||||
{
|
||||
//Display context menu to reset the display reset();
|
||||
}
|
||||
|
||||
public void mousePressed( MouseEvent e ) {}
|
||||
public void mouseReleased( MouseEvent e ) {}
|
||||
public void mouseEntered( MouseEvent e ) {}
|
||||
public void mouseExited( MouseEvent e ){}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingDeleted( Setting setting ) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user