main difference: music selection screen now completely functional; other

refactoring and changes to make better use of the framework were made;
some cleanup happened;
This commit is contained in:
2018-08-18 22:19:08 -05:00
parent fa8dd9622f
commit d7008796f4
21 changed files with 521 additions and 470 deletions

View File

@@ -86,7 +86,7 @@ public class MusicController extends Observable implements OnCompletionListener,
public void skip() {
currentlyPlayingIndex++;
if (shuffle) {
shuffle(false);
shuffle();
}
loadMusic();
}
@@ -97,7 +97,7 @@ public class MusicController extends Observable implements OnCompletionListener,
public void previous() {
currentlyPlayingIndex--;
if (shuffle) {
shuffle(false);
shuffle();
}
loadMusic();
}
@@ -106,7 +106,7 @@ public class MusicController extends Observable implements OnCompletionListener,
public void onCompletion(Music music) {
if (autoPlay) {
if (shuffle) {
shuffle(false);
shuffle();
} else {
currentlyPlayingIndex++;
}
@@ -117,18 +117,14 @@ public class MusicController extends Observable implements OnCompletionListener,
/**
* Shuffles the controller whether the shuffle boolean is true or false.
* @param load whether this method should also make sure to load the music, dispose of the last one, etc. Normally called unless you plan to manually call it elsewhere.
*/
public void shuffle(boolean load) {
public void shuffle() {
Gdx.app.debug("MusicListController", "shuffled.");
if (musicList.getTotal() == 0) {
currentlyPlayingIndex = 0;
} else {
currentlyPlayingIndex = rand.nextInt(musicList.getTotal());
}
if (load) {
loadMusic();
}
}
public void setAutoPlay(boolean autoPlay) {
@@ -152,6 +148,7 @@ public class MusicController extends Observable implements OnCompletionListener,
*/
public void loadMusic() {
Gdx.app.debug("MusicListController", "music is being loaded and listeners are being notified.");
boolean playing = isPlaying();
musicHeader = null;
if (music != null) {
music.dispose();
@@ -169,7 +166,7 @@ public class MusicController extends Observable implements OnCompletionListener,
setChanged();
notifyObservers(states.LOADED);
if (autoPlay) {
if (playing) {
play();
}
}
@@ -195,9 +192,12 @@ public class MusicController extends Observable implements OnCompletionListener,
public void update(Observable o, Object arg) {
if (o == musicList) {
if (shuffle) {
shuffle(false);
shuffle();
}
loadMusic();
if (autoPlay) {
play();
}
}
}

View File

@@ -1,10 +1,12 @@
package zero1hd.rhythmbullet.audio;
import java.util.Comparator;
import java.util.Observable;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Sort;
import zero1hd.rhythmbullet.audio.processor.AudioProcessor;
import zero1hd.rhythmbullet.audio.processor.WAVAudioProcessor;
@@ -20,19 +22,30 @@ public class MusicList extends Observable {
private AudioProcessorFactory audioProcFactory;
private volatile boolean searched;
private String searchPath;
private Comparator<FileHandle> compare;
public MusicList(AudioProcessorFactory audioProcessorFactory, String searchPath) {
this.audioProcFactory = audioProcessorFactory;
musicList = new Array<>();
setSearchPath(searchPath);
compare = new Comparator<FileHandle>() {
@Override
public int compare(FileHandle o1, FileHandle o2) {
return o1.nameWithoutExtension().compareTo(o2.nameWithoutExtension());
}
};
}
/**
* Wrapper method that uses async refresh.
* Also notifies listeners that are on the main thread.
* @param refresh does a search whether or not path has changed.
* @param refresh does a search whether or not path has changed and whether or not this list has searched before this.
*/
public void asyncSearch(boolean refresh) {
if (refresh) {
if (searchThread != null) {
if (!searchThread.start()) {
searchThread.stop();
@@ -45,7 +58,6 @@ public class MusicList extends Observable {
}
} else {
if (searched && !hasChanged()) {
setChanged();
notifyObservers();
} else {
asyncSearch(true);
@@ -54,7 +66,7 @@ public class MusicList extends Observable {
}
public void setSearchPath(String searchPath) {
hasChanged();
setChanged();
this.searchPath = searchPath;
}
@@ -88,6 +100,9 @@ public class MusicList extends Observable {
Gdx.app.debug("MusicList", "Warning, this list has not completed it's search...");
Thread.dumpStack();
}
if (musicList.size == 0) {
return null;
}
return newAudioProcessor(musicList.get(index));
}
@@ -97,6 +112,9 @@ public class MusicList extends Observable {
Gdx.app.debug("MusicList", "Warning, this list has not completed it's search...");
Thread.dumpStack();
}
if (musicList.size == 0) {
return null;
}
return musicList.get(index);
}
@@ -130,22 +148,13 @@ public class MusicList extends Observable {
@Override
public void run() {
Array<FileHandle> obtainedAudioFiles = recursiveMusicSearch(directory);
if (Gdx.files.external("RhythmBullet").exists()) {
if (!Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3").exists()) {
Gdx.files.internal("music/Alan Walker - Spectre.mp3").copyTo(Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3"));
}
} else {
Gdx.files.internal("music/Alan Walker - Spectre.mp3").copyTo(Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3"));
}
Sort.instance().sort(obtainedAudioFiles, compare);
if (work) {
musicList = obtainedAudioFiles;
musicList.add(Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3"));
if (work) {
searched = true;
Gdx.app.debug("MusicList", "recursive async search completed.");
setChanged();
notifyObservers();
}
searched = true;
Gdx.app.debug("MusicList", "recursive async search completed.");
setChanged();
notifyObservers();
}
}

View File

@@ -3,6 +3,7 @@ package zero1hd.rhythmbullet.audio;
import java.util.Observable;
import java.util.Observer;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
@@ -74,10 +75,11 @@ public class MusicMetadataController extends Observable implements Disposable, O
private class MetadataLoadingThread implements Runnable {
private Thread thread;
private String name = "Metadata-Load";
private volatile boolean work;
private volatile boolean work = true;
@Override
public void run() {
Gdx.app.debug(name, "loading...");
searching = true;
for (int i = 0; i < metadataArray.size; i++) {
metadataArray.get(i).dispose();
@@ -101,6 +103,8 @@ public class MusicMetadataController extends Observable implements Disposable, O
}
if (work) {
searching = false;
Gdx.app.debug(name, "load complete.");
setChanged();
notifyObservers();
}
}
@@ -123,7 +127,6 @@ public class MusicMetadataController extends Observable implements Disposable, O
@Override
public void update(Observable o, Object arg) {
if (o == musicList) {
loadingThread.stop();
loadAudioMetadata();
}
}

View File

@@ -46,7 +46,7 @@ public interface AudioMetadata extends Disposable {
public int getLength();
/**
*
* Requires a OpenGL context.
* @return the texture. Needs to be loaded before hand or else will return null.
*/
public Texture getAlbumCover();

View File

@@ -1,6 +1,8 @@
package zero1hd.rhythmbullet.audio.metadata;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
@@ -11,6 +13,7 @@ import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.id3.ID3v23FieldKey;
import org.jaudiotagger.tag.id3.ID3v23Tag;
import org.jaudiotagger.tag.images.Artwork;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
@@ -22,6 +25,7 @@ public class MP3Metadata implements AudioMetadata {
private int length;
private Texture albumCover;
private FileHandle fileHandle;
private byte[] imageData;
public MP3Metadata(FileHandle fileHandle) {
this.fileHandle = fileHandle;
@@ -37,16 +41,18 @@ public class MP3Metadata implements AudioMetadata {
}
tag = (ID3v23Tag) mp3file.getTagAndConvertOrCreateAndSetDefault();
length = mp3file.getAudioHeader().getTrackLength();
int min = (int) (length/60);
duration = (length/60) + ":" + (length - (min*60));
SimpleDateFormat f = new SimpleDateFormat("m:ss");
duration = f.format(new Date(length*1000));
author = tag.getFirst(ID3v23FieldKey.ARTIST);
genre = tag.getFirst(ID3v23FieldKey.GENRE);
title = tag.getFirst(ID3v23FieldKey.TITLE);
if (title.isEmpty()) {
title = fileHandle.nameWithoutExtension();
}
} catch (IOException | CannotWriteException | CannotReadException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
Gdx.app.error("MP3Metadata", "Failed to read metadata of file: " + fileHandle.name());
}
@@ -57,25 +63,17 @@ public class MP3Metadata implements AudioMetadata {
MP3File mp3file;
try {
mp3file = (MP3File) AudioFileIO.read(fileHandle.file());
byte[] imageData = mp3file.getTag().getFirstArtwork().getBinaryData();
Pixmap pixmap = new Pixmap(imageData, 0, imageData.length);
albumCover = new Texture(pixmap);
pixmap.dispose();
Artwork art = mp3file.getTag().getFirstArtwork();
if (art != null) {
imageData = art.getBinaryData();
}
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
e.printStackTrace();
}
}
@Override
public void unloadAlbumCover() {
if (albumCover != null) {
albumCover.dispose();
albumCover = null;
}
}
@Override
public String getAuthor() {
return author;
@@ -101,8 +99,22 @@ public class MP3Metadata implements AudioMetadata {
return genre;
}
@Override
public void unloadAlbumCover() {
if (albumCover != null) {
albumCover.dispose();
albumCover = null;
}
}
@Override
public Texture getAlbumCover() {
if (albumCover == null && imageData != null) {
Pixmap pixmap = new Pixmap(imageData, 0, imageData.length);
albumCover = new Texture(pixmap);
pixmap.dispose();
imageData = null;
}
return albumCover;
}

View File

@@ -1,6 +1,8 @@
package zero1hd.rhythmbullet.audio.metadata;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
@@ -10,6 +12,7 @@ import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.images.Artwork;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
@@ -21,6 +24,7 @@ public class WAVMetadata implements AudioMetadata {
private int length;
private Texture albumCover;
private FileHandle fileHandle;
private byte[] imageData;
public WAVMetadata(FileHandle fileHandle) {
this.fileHandle = fileHandle;
@@ -28,13 +32,16 @@ public class WAVMetadata implements AudioMetadata {
try {
AudioFile wav = AudioFileIO.read(fileHandle.file());
length = wav.getAudioHeader().getTrackLength();
int min = (int) (length/60);
this.duration = (length/60) + ":" + (length - (min*60));
SimpleDateFormat f = new SimpleDateFormat("m:ss");
duration = f.format(new Date(length*1000));
Tag tag = wav.getTag();
title = tag.getFirst(FieldKey.TITLE);
author = tag.getFirst(FieldKey.ARTIST);
genre = tag.getFirst(FieldKey.GENRE);
if (title.isEmpty()) {
title = fileHandle.nameWithoutExtension();
}
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
Gdx.app.error("WAVMetadata", "Failed to read metadata of file: " + fileHandle.name());
}
@@ -44,11 +51,10 @@ public class WAVMetadata implements AudioMetadata {
public void loadAlbumCover() {
try {
AudioFile wav = AudioFileIO.read(fileHandle.file());
byte[] imageData = wav.getTag().getFirstArtwork().getBinaryData();
Pixmap pixmap = new Pixmap(imageData, 0, imageData.length);
albumCover = new Texture(pixmap);
pixmap.dispose();
Artwork art = wav.getTag().getFirstArtwork();
if (art != null) {
imageData = art.getBinaryData();
}
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
e.printStackTrace();
@@ -82,6 +88,12 @@ public class WAVMetadata implements AudioMetadata {
@Override
public Texture getAlbumCover() {
if (albumCover == null && imageData != null) {
Pixmap pixmap = new Pixmap(imageData, 0, imageData.length);
albumCover = new Texture(pixmap);
pixmap.dispose();
imageData = null;
}
return albumCover;
}
@Override

View File

@@ -21,13 +21,13 @@ public class DoubleHorizontalVisualizer implements Disposable {
private int binsPerBar;
private float offset;
private int boundaryThickness;
private float baseSensitivity;
private float targetDelta;
private float spacePercentage = 0.7f;
private int barCount = 90;
private float barChangeRate = 14f;
private int smoothRange = 1;
private int binsToInclude = 180;
private float baseSensitivity = 0.009f;
private int barCount = 120;
private float barChangeRate = 7f;
private int smoothRange = 2;
private int binsToInclude = 120;
private Color color = new Color(0.5f, 0.6f, 0.8f, 0.46f);
/**
*
@@ -35,11 +35,11 @@ public class DoubleHorizontalVisualizer implements Disposable {
* @param width the width of the visualizer.
* @param spacePercentage the percentage of a bar that should be space.
*/
public DoubleHorizontalVisualizer(int width, int height, float baseSensitivity, int boundaryThickness, int targetFPS, MusicController musicController, PCMSystem PCMSystem) {
public DoubleHorizontalVisualizer(int width, int height, float heightSensitivity, int boundaryThickness, int targetFPS, MusicController musicController, PCMSystem PCMSystem) {
this.barWidth = width/barCount;
this.spaceBetweenBars = MathUtils.round(barWidth * spacePercentage);
this.barWidth -= spaceBetweenBars;
this.baseSensitivity = baseSensitivity;
this.baseSensitivity *= heightSensitivity;
pcm = PCMSystem;
binsPerBar = (binsToInclude/barCount);
this.width = width;
@@ -55,11 +55,10 @@ public class DoubleHorizontalVisualizer implements Disposable {
public void act(float delta) {
float[] freqBins = pcm.getFrequencyBins();
for (int bar = 0; bar < amplitudes.length; bar++) {
float normalizedAmplitude = 0;
amplitudes[bar] = 0;
for (int freq = bar*binsPerBar; freq < (bar*binsPerBar) + binsPerBar; freq++) {
normalizedAmplitude += Math.abs(freqBins[freq]);
amplitudes[bar] += Math.abs(freqBins[freq]) * baseSensitivity;
}
amplitudes[bar] += normalizedAmplitude * baseSensitivity;
amplitudes[bar] /= binsPerBar;
}
for (int bar = 0; bar < barHeights.length; bar++) {
@@ -78,13 +77,22 @@ public class DoubleHorizontalVisualizer implements Disposable {
int pixelsMoved = 0;
pixelsMoved = MathUtils.round(amplitudes[bar] - barHeights[bar]);
pixelsMoved = MathUtils.floor(pixelsMoved*targetDelta*barChangeRate);
int difference = MathUtils.round(amplitudes[bar] - barHeights[bar]);
pixelsMoved = MathUtils.floor(difference*targetDelta*barChangeRate);
if (pixelsMoved >= 0) {
if (barHeights[bar] + pixelsMoved > amplitudes[bar]) {
barHeights[bar] += MathUtils.round(difference*targetDelta);
} else {
barHeights[bar] += pixelsMoved;
}
} else {
if (barHeights[bar] + pixelsMoved < amplitudes[bar]) {
barHeights[bar] += MathUtils.round(difference*targetDelta);
} else {
barHeights[bar] += pixelsMoved;
}
}
barHeights[bar] += pixelsMoved;
if (barHeights[bar] < 0) barHeights[bar] = 0;
}
}
@@ -103,7 +111,7 @@ public class DoubleHorizontalVisualizer implements Disposable {
for (int bar = 0; bar < barCount; bar++) {
shapeRenderer.setColor(color);
shapeRenderer.rect(offset + (spaceBetweenBars+barWidth)*bar, y+height, barWidth, barHeights[bar]);
shapeRenderer.rect(offset + (spaceBetweenBars+barWidth)*bar, y-barHeights[barHeights.length - 1 - bar], barWidth, barHeights[barHeights.length - 1 - bar]);
shapeRenderer.rect(offset + (spaceBetweenBars+barWidth)*bar, y, barWidth, -barHeights[barHeights.length - 1 - bar]);
}
shapeRenderer.end();
Gdx.gl.glDisable(GL20.GL_BLEND);

View File

@@ -66,4 +66,8 @@ public class Page extends Group implements Disposable {
public void dispose() {
Gdx.app.debug(getClass().getSimpleName(), "Disposing...");
}
public void simpleDebug(String message) {
Gdx.app.debug(getClass().getSimpleName(), message);
}
}

View File

@@ -0,0 +1,81 @@
package zero1hd.rhythmbullet.graphics.ui.components;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox;
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import zero1hd.rhythmbullet.audio.MusicController;
public class MusicControls extends HorizontalGroup {
private ImageButton reverse, forward;
private CheckBox shuffle, play;
public MusicControls(Skin skin, final MusicController sc) {
reverse = new ImageButton(skin, "rewind-button");
reverse.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
sc.previous();
}
});
addActor(reverse);
play = new CheckBox(null, skin, "play-button") {
@Override
public void act(float delta) {
if (sc.hasSongLoaded()) {
play.setChecked(sc.isPlaying());
} else {
play.setChecked(false);
}
super.act(delta);
}
};
play.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if (play.isChecked()) {
sc.play();
} else {
sc.pause();
}
super.clicked(event, x, y);
}
});
addActor(play);
forward = new ImageButton(skin, "fast-forward-button");
forward.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
sc.skip();
}
});
addActor(forward);
shuffle = new CheckBox(null, skin, "shuffle-button") {
@Override
public void act(float delta) {
shuffle.setChecked(sc.isShuffle());
super.act(delta);
}
};
shuffle.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
if (shuffle.isChecked()) {
sc.setShuffle(true);
} else {
sc.setShuffle(false);
}
}
});
addActor(shuffle);
space(15);
setSize(getMinWidth(), getMinHeight());
}
}

View File

@@ -1,108 +0,0 @@
package zero1hd.rhythmbullet.graphics.ui.components;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Array;
import zero1hd.rhythmbullet.audio.metadata.AudioMetadata;
public class MusicSelectable extends Button {
private Vector2 actualCoords;
private Image album;
private Table informationTable;
private ShortenedLabel name, artist;
private Label time;
private float timeSinceOnScreen;
private AudioMetadata metadata;
private Texture defaultAlbumArt;
private Array<MusicSelectable> queueList;
public MusicSelectable(Skin skin, Texture defaultAlbumArt, AudioMetadata metadata,
Array<MusicSelectable> queueList) {
super(skin, "music-selectable");
this.metadata = metadata;
this.defaultAlbumArt = defaultAlbumArt;
this.queueList = queueList;
album = new Image(defaultAlbumArt);
add(album).expand().left();
informationTable = new Table();
name = new ShortenedLabel(metadata.getTitle(), skin, "default-font", skin.getColor("default"));
informationTable.add(name).colspan(2).expandX();
informationTable.row();
artist = new ShortenedLabel(metadata.getTitle(), skin, "sub-font", skin.getColor("default"));
informationTable.add(artist).expandX();
time = new Label(metadata.getDuration(), skin, "sub-font", skin.getColor("default"));
informationTable.add(time).expandX();
add(informationTable).expand().fill();
}
@Override
public void act(float delta) {
actualCoords.x = getX() + getParent().getX();
actualCoords.y = getY() + getParent().getY();
if (actualCoords.y < 0 - getHeight() || actualCoords.y > getStage().getHeight()
|| actualCoords.x < 0 - getWidth() || actualCoords.x > getStage().getWidth()) {
offScreenAct(delta);
} else {
onScreenAct(delta);
}
super.act(delta);
}
@Override
public void draw(Batch batch, float parentAlpha) {
synchronized (album) {
super.draw(batch, parentAlpha);
}
}
public void onScreenAct(float delta) {
timeSinceOnScreen = 0;
if (!queueList.contains(this, true)) {
synchronized (queueList) {
queueList.add(this);
notify();
}
}
}
public void offScreenAct(float delta) {
if (metadata.getAlbumCover() != null) {
timeSinceOnScreen += delta;
if (timeSinceOnScreen >= 2) {
album.setDrawable(new TextureRegionDrawable(new TextureRegion(defaultAlbumArt)));
metadata.unloadAlbumCover();
}
}
}
public void loadAlbumCover() {
metadata.loadAlbumCover();
Texture texture = defaultAlbumArt;
if (metadata.getAlbumCover() != null) {
texture = metadata.getAlbumCover();
}
synchronized (album) {
album.setDrawable(new TextureRegionDrawable(new TextureRegion(texture)));
}
}
public AudioMetadata getMetadata() {
return metadata;
}
public FileHandle getFileHandle() {
return metadata.getFileHandle();
}
}

View File

@@ -1,59 +0,0 @@
package zero1hd.rhythmbullet.graphics.ui.components;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.scenes.scene2d.ui.ButtonGroup;
import com.badlogic.gdx.utils.Array;
import zero1hd.rhythmbullet.audio.metadata.AudioMetadata;
public class MusicSelectableButtonGroup extends ButtonGroup<MusicSelectable> {
private Array<MusicSelectable> buttons;
public MusicSelectableButtonGroup() {
buttons = getButtons();
}
public void setChecked(AudioMetadata metadata) {
if (metadata == null) throw new IllegalArgumentException("metadata can't be null.");
MusicSelectable button;
for (int i = 0; i < buttons.size; i++) {
button = buttons.get(i);
if (button.getMetadata() == metadata) {
button.setChecked(true);
return;
}
}
}
public void setChecked(FileHandle fileHandle) {
if (fileHandle == null) throw new IllegalArgumentException("fileHandle can't be null.");
MusicSelectable button;
for (int i = 0; i < buttons.size; i++) {
button = buttons.get(i);
if (button.getFileHandle() == fileHandle) {
button.setChecked(true);
return;
}
}
}
public void selectNext() {
int index = getCheckedIndex() + 1;
if (index == buttons.size) {
index = 0;
}
buttons.get(index).setChecked(true);
}
public void selectPrevious() {
int index = getCheckedIndex() - 1;
if (index == -1) {
index = buttons.size -1;
}
buttons.get(index).setChecked(true);
}
public void setChecked(int index) {
buttons.get(index).setChecked(true);
}
}

View File

@@ -1,61 +0,0 @@
package zero1hd.rhythmbullet.graphics.ui.components;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
public class ShortenedLabel extends Label {
private String originalText;
private int targetWidth;
private GlyphLayout gl;
private BitmapFont font;
private Vector2 size;
public ShortenedLabel(CharSequence text, Skin skin, String fontName, Color color) {
super(null, skin, fontName, color);
originalText = text.toString();
font = skin.getFont(fontName);
if (text != null) {
gl = new GlyphLayout(skin.getFont(fontName), text);
}
size = new Vector2();
setWrap(true);
}
public void resize() {
setToOriginalText();
String text = getText().toString();
while (gl.width > targetWidth && (text.length() - 4) > 0) {
text = text.substring(0, text.length() - 4).concat("...");
gl.setText(font, text);
}
setText(text);
}
public void setToOriginalText() {
setText(originalText);
gl.setText(font, originalText);
}
@Override
public void layout() {
super.layout();
size.x = getWidth();
size.y = getHeight();
targetWidth = (int) getStage().stageToScreenCoordinates(size).x;
resize();
}
public void setOriginalText(String originalText) {
this.originalText = originalText;
gl.setText(font, originalText);
}
public int getTargetWidth() {
return targetWidth;
}
}

View File

@@ -3,9 +3,12 @@ package zero1hd.rhythmbullet.util;
public interface ScreenConfiguration {
public void setFramesPerSecond(int fps);
public void setVsync(boolean useVsync);
public int getTargetFramesPerSecond();
public int getFramesPerSecond();
/**
* @param useVsync whether or not to use vSync.
*/
public void setVsync(boolean useVsync);
public boolean getVsync();
@@ -22,4 +25,9 @@ public interface ScreenConfiguration {
public void setWindowLocationY(int y);
public void setWindowLocation(int x, int y);
/**
* Restarts the application.
*/
public void restart();
}