Related
I am working on a simple 2D infinite runner game. I am trying to get the player to move in any direction without needing to touch the player specifically. I want the game to find where the user touches and then allow the user to control the player from there. At the moment the player moves but only when the user is touching the player directly which makes it difficult for the user to see the actual player when playing and trying to dodge obstacles.
Here is the code I currently have:
public boolean recieveTouch(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int action = event.getAction();
int x = (int) event.getX(); // or getRawX();
int y = (int) event.getY();
int h2 = bitmap2.getHeight();
int w2 = bitmap2.getWidth();
float xRatio2 = (Constants.SCREEN_WIDTH / 2)-( w2 / 2);
float yRatio2 = (Constants.SCREEN_HEIGHT / 2)-( h2 / 2) + (Constants.SCREEN_WIDTH/4 + (Constants.SCREEN_WIDTH/6)- Constants.SCREEN_HEIGHT/10);
int h55 = bitmap55.getHeight();
int w55 = bitmap55.getWidth();
int h66 = bitmap66.getHeight();
int w66 = bitmap66.getWidth();
float xRatio55 = ((Constants.SCREEN_WIDTH / 4)-( w55 / 4));
float yRatio55 = (((Constants.SCREEN_HEIGHT / 2) + (h55 / 2)) + (Constants.SCREEN_HEIGHT/6));
float xRatio66 = ((Constants.SCREEN_WIDTH / 2)+( w66 / 4) + (Constants.SCREEN_HEIGHT/24));
float yRatio66 = (((Constants.SCREEN_HEIGHT / 2) + (h66 / 2)) + (Constants.SCREEN_HEIGHT/6));
//help
int h5 = bitmap4.getHeight();
int w5 = bitmap4.getWidth();
float xRatio5 = ((Constants.SCREEN_WIDTH / 4) - (w5 / 1));
float yRatio5 = (((Constants.SCREEN_HEIGHT / 8) - (h5 / 1)));
long pressTime = System.currentTimeMillis();
if (!gameOver && player.getRectangle().contains((int) event.getX(), (int) event.getY()))
movingPlayer = true;
if (gameOver && System.currentTimeMillis() - gameOverTime >= 0) {
if (x >= xRatio2 && x < (xRatio2 + bitmap2.getWidth())
&& y >= yRatio2 && y < (yRatio2 + bitmap2.getHeight())) {
if (GamePanel.Ad1 == 1) {
MainActivity.click.start();
MainActivity.mAd = MobileAds.getRewardedVideoAdInstance(mActivityRef.get());
loadAd();
MainActivity.mAd.show();
//Appodeal.show(mActivityRef.get(), Appodeal.REWARDED_VIDEO);
}
}
if (x >= xRatio55 && x < (xRatio55 + bitmap55.getWidth())
&& y >= yRatio55 && y < (yRatio55 + bitmap55.getHeight())) {
MainActivity.click.start();
reset();
gameOver = false;
orientationData.newGame();
}
if (x >= xRatio66 && x < (xRatio66 + bitmap66.getWidth())
&& y >= yRatio66 && y < (yRatio66 + bitmap66.getHeight())) {
MainActivity.click.start();
SceneManager.ACTIVE_SCENE = 4;
MainActivity.mInterstitialAd.loadAd((new AdRequest.Builder().build()));
MainActivity.mInterstitialAd.show();
//Appodeal.show(mActivityRef.get(), Appodeal.INTERSTITIAL);
if (GamePanel.YelowBird == 4) {
GamePanel.YelowBird = 2;
GamePanel.RedBird = 1;
}
reset();
gameOver = false;
}
if (x >= xRatio5 && x < (xRatio5 + bitmap4.getWidth())
&& y >= yRatio5 && y < (yRatio5 + bitmap4.getHeight())) {
if (GamePanel.Help == 0) {
GamePanel.Help = 1;
if (GamePanel.Help == 1) {
MainActivity.click.start();
orientationData.register();
}
} else if (GamePanel.Help == 1) {
GamePanel.Help = 0;
if (GamePanel.Help == 0) {
MainActivity.click.start();
orientationData.pause();
}
}
} return true;
}
break;
case MotionEvent.ACTION_MOVE:
if (GamePanel.NinjaBird == 4) {
if (!gameOver)
playerPoint.set((int) event.getX(), (int) event.getY());
} else {
if (!gameOver && movingPlayer)
playerPoint.set((int) event.getX(), (int) event.getY());
}
break;
case MotionEvent.ACTION_UP:
movingPlayer = false;
break;
}
return false;
}
if anyone else wants to do a similar thing:
i changed the following line
from this:
if (!gameOver && movingPlayer)
playerPoint.set((int) event.getX(), (int) event.getY());
to this:
if (!gameOver && movingPlayer)
playerPoint.set((int) event.getX(), (int) event.getY()+200);
so you move the player by touching 200 pixels under it.
This class uses graphics to print a maze. The program will be run 3 times. After the first, I save a steps array that counts the number of times the character steps over a spot. I then write this array to a file. Before the next run, I open the file. I need to use the contents of the file to "learn" where not to go for the next trial (ie. avoid dead ends, find quickest path to finish).
I have a method hasBadBranch() that I want to return true for all intersections that have branches (north, south, east, and west of the intersection) with "steps" > 1. I'm getting array index out of bounds and the character no longer goes through the maze correctly when I add the hasBadBranch condition in my solve() method. If anyone sees any flaws in my logic, I would greatly appreciate the feedback. Thanks.
public class Maze extends JFrame {
private static final int MAX_WIDTH = 255;
private static final int MAX_HEIGHT = 255;
private char[][] maze = new char[MAX_HEIGHT][MAX_WIDTH];
private int[][] steps = new int[MAX_HEIGHT][MAX_WIDTH];
private Random random = new Random();
private JPanel mazePanel = new JPanel();
private int width = 0;
private int height = 0;
private boolean step = false;
private boolean timerFired = false;
private Timer timer;
private final int TIMER_DELAY = 20;
private final int SPRITE_WIDTH = 25;
private final int SPRITE_HEIGHT = 25;
private BufferedImage mazeImage;
private ImageIcon ground = new ImageIcon("sprites/ground.png");
private ImageIcon wall1 = new ImageIcon("sprites/cactus.png");
private ImageIcon wall2 = new ImageIcon("sprites/rock.png");
private ImageIcon finish = new ImageIcon("sprites/well.png");
private ImageIcon south1 = new ImageIcon("sprites/cowboy-forward-1.png");
private ImageIcon south2 = new ImageIcon("sprites/cowboy-forward-2.png");
private ImageIcon north1 = new ImageIcon("sprites/cowboy-back-1.png");
private ImageIcon north2 = new ImageIcon("sprites/cowboy-back-2.png");
private ImageIcon west1 = new ImageIcon("sprites/cowboy-left-1.png");
private ImageIcon west2 = new ImageIcon("sprites/cowboy-left-2.png");
private ImageIcon east1 = new ImageIcon("sprites/cowboy-right-1.png");
private ImageIcon east2 = new ImageIcon("sprites/cowboy-right-2.png");
private long startTime;
private long currentTime;
private static final int MAX_TIME = 500000;
/**
* Constructor for class Maze. Opens a text file containing the maze, then
* attempts to solve it.
*
* #param fname String value containing the filename of the maze to open.
*/
//Notes to user:
//delete steps.txt BEFORE testing begins and AFTER third run of program
//use appropriate file paths
public Maze(String fname) throws FileNotFoundException, IOException {
openMaze(fname);
mazeImage = printMaze();
readInFile();
timer = new Timer(TIMER_DELAY, new TimerHandler()); // setup a Timer to slow the animation down.
timer.start();
addWindowListener(new WindowHandler()); // listen for window event windowClosing
setTitle("Cowboy Maze");
setSize(width * SPRITE_WIDTH + 10, height * SPRITE_HEIGHT + 30);
setVisible(true);
add(mazePanel);
setContentPane(mazePanel);
solveMaze();
}
public void readInFile() throws FileNotFoundException, IOException {
//Note to user: adjust file path accordingly
File stepsFile = new File("C:\\Users\\Ashley Bertrand\\Desktop\\Data Structures\\Lab6\\mazeStartSourceMazesGraphics\\steps.txt");
if (stepsFile.isFile()) {
Scanner scanner = new Scanner(stepsFile);
int lineCount = 0;
while (scanner.hasNextLine()) {
String[] currentLine = scanner.nextLine().trim().split("\\s+");
for (int i = 0; i < currentLine.length; i++) {
steps[lineCount][i] = Integer.parseInt(currentLine[i]);
}
lineCount++;
}
System.out.println("Contents of steps.txt:");
for (int m = 0; m < width; m++) {
for (int n = 0; n < height; n++) {
System.out.print(steps[m][n]);
}
System.out.println();
}
System.out.println();
} else {
System.out.println("Running first trial so steps.txt does not exist");
}
}
/**
* Called from the operating system. If no command line arguments are
* supplied, the method displays an error message and exits. Otherwise, a
* new instance of Maze() is created with the supplied filename from the
* command line.
*
* #param args[] Command line arguments, the first of which should be the
* filename to open.
*/
public static void main(String[] args) throws FileNotFoundException, IOException {
int runny = 1;
if (args.length > 0) {
new Maze(args[0]);
} else {
System.out.println();
System.out.println("Usage: java Maze <filename>.");
System.out.println("Maximum Maze size:" + MAX_WIDTH + " x " + MAX_HEIGHT + ".");
System.out.println();
System.exit(1);
}
}
/**
* Finds the starting location and passes it to the recursive algorithm
* solve(x, y, facing). The starting location should be the only '.' on the
* outer wall of the maze.
*/
public void solveMaze() throws FileNotFoundException {
boolean startFound = false;
if (!startFound) {
for (int i = 0; i < width; i++) { // look for the starting location on the top and bottom walls of the Maze.
if (maze[0][i] == '.') {
maze[0][i] = 'S';
steps[0][i]++;
preSolve(i, 0, "south");
startFound = true;
} else if (maze[height - 1][i] == '.') {
maze[height - 1][i] = 'S';
steps[height - 1][i]++;
preSolve(i, height - 1, "north");
startFound = true;
}
}
}
if (!startFound) {
for (int i = 0; i < height; i++) { // look for the starting location on the left and right walls of the Maze.
if (maze[i][0] == '.') {
maze[i][0] = 'S';
steps[i][0]++;
preSolve(0, i, "east");
startFound = true;
} else if (maze[i][width - 1] == '.') {
maze[i][width - 1] = 'S';
steps[i][width - 1]++;
preSolve(width - 1, i, "west");
startFound = true;
}
}
}
if (!startFound) {
System.out.println("Start not found!");
}
}
public void preSolve(int x, int y, String facing) throws FileNotFoundException {
Scanner input = new Scanner(System.in);
System.out.println("Press 1 to start");
input.nextLine();
startTime = System.currentTimeMillis();
solve(x, y, facing);
}
/**
* Recursive algorithm to solve a Maze. Places an X at locations already
* visited. This algorithm is very inefficient, it follows the right hand
* wall and will never find the end if the path leads it in a circle.
*
* #param x int value of the current X location in the Maze.
* #param y int value of the current Y location in the Maze.
* #param facing String value holding one of four cardinal directions
* determined by the current direction facing.
*/
private void solve(int x, int y, String facing) throws FileNotFoundException {
Graphics2D g2 = (Graphics2D) mazePanel.getGraphics(); //don't mess with the next
while (!timerFired) { // wait for the timer.
try {
Thread.sleep(10);
} catch (Exception e) {
}
}
timerFired = false;
currentTime = System.currentTimeMillis();
if ((currentTime - startTime) > MAX_TIME) {
closingMethod();
}
if (maze[y][x] != 'F') { //this is if it doesn't find the finish on a turn.........
g2.drawImage(mazeImage, null, 0, 0);
g2.drawImage(printGuy(facing), x * SPRITE_WIDTH, y * SPRITE_HEIGHT, null, null);
mazePanel.setSize(width * SPRITE_WIDTH + 10, height * SPRITE_HEIGHT + 30);
maze[y][x] = 'X'; // mark this spot as visited. This is how you can keep track of where you've been.
if (facing.equals("east")) {
if (maze[y + 1][x] != '#' && maze[y + 1][x] != '%' && maze[y + 1][x] != 'S' && !hasBadBranch(y+1, x)) {
steps[y + 1][x]++;
solve(x, y + 1, "south");
} else if (maze[y][x + 1] != '#' && maze[y][x + 1] != '%' && maze[y][x + 1] != 'S' && !hasBadBranch(y, x+1)) {
steps[y][x + 1]++;
solve(x + 1, y, "east");
} else {
solve(x, y, "north");
}
} else if (facing.equals("west")) {
if (maze[y - 1][x] != '#' && maze[y - 1][x] != '%' && maze[y - 1][x] != 'S' && !hasBadBranch(y-1, x)) {
steps[y - 1][x]++;
solve(x, y - 1, "north");
} else if (maze[y][x - 1] != '#' && maze[y][x - 1] != '%' && maze[y][x - 1] != 'S'&& !hasBadBranch(y, x-1)) {
steps[y][x - 1]++;
solve(x - 1, y, "west");
} else {
solve(x, y, "south");
}
} else if (facing.equals("south")) {
if (maze[y][x - 1] != '#' && maze[y][x - 1] != '%' && maze[y][x - 1] != 'S' && !hasBadBranch(y, x-1)) {
steps[y][x - 1]++;
solve(x - 1, y, "west");
} else if (maze[y + 1][x] != '#' && maze[y + 1][x] != '%' && maze[y + 1][x] != 'S' && !hasBadBranch(y+1, x)) {
steps[y + 1][x]++;
solve(x, y + 1, "south");
} else {
solve(x, y, "east");
}
} else if (facing.equals("north")) {
if (maze[y][x + 1] != '#' && maze[y][x + 1] != '%' && maze[y][x + 1] != 'S' && !hasBadBranch(y, x+1)) {
steps[y][x + 1]++;
solve(x + 1, y, "east");
} else if (maze[y - 1][x] != '#' && maze[y - 1][x] != '%' && maze[y - 1][x] != 'S' && !hasBadBranch(y-1, x)) {
steps[y - 1][x]++;
solve(x, y - 1, "north");
} else {
solve(x, y, "west");
}
}
} else {
writeToFile();
System.out.println("Found the finish!");
currentTime = System.currentTimeMillis();
long endTime = currentTime - startTime;
long finalTime = endTime / 1000;
System.out.println("Final Time = " + finalTime);
}
}
public boolean hasBadBranch(int y, int x) {
//9999 will be used to tell character not to take that branch
if (steps[y][x] > 1) {
if (steps[y + 1][x] > 1) {
steps[y + 1][x] = 9999;
return true; //south
}
if (steps[y - 1][x] > 1) {
steps[y - 1][x] = 9999;
return true; //north
}
if (steps[y][x + 1] > 1) {
steps[y][x + 1] = 9999;
return true; //east
}
if (steps[y][x - 1] > 1) {
steps[y][x - 1] = 9999;
return true; //west
}
}
return false;
}
/**
* Opens a text file containing a maze and stores the data in the 2D char
* array maze[][].
*
* #param fname String value containing the file name of the maze to open.
*/
public void openMaze(String fname) {
String in = "";
int i = 0;
try {
Scanner sc = new Scanner(new File(fname));
while (sc.hasNext()) {
in = sc.nextLine();
in = trimWhitespace(in);
if (in.length() <= MAX_WIDTH && i < MAX_HEIGHT) {
for (int j = 0; j < in.length(); j++) {
if (in.charAt(j) == '#') { // if this spot is a wall, randomize the wall peice to display
if (random.nextInt(2) == 0) {
maze[i][j] = '#';
} else {
maze[i][j] = '%';
}
} else {
maze[i][j] = in.charAt(j);
}
}
} else {
System.out.println("Maximum maze size exceeded: (" + MAX_WIDTH + " x " + MAX_HEIGHT + ")!");
System.exit(1);
}
i++;
}
width = in.length();
height = i;
System.out.println("(" + width + " x " + height + ") maze opened.");
System.out.println();
sc.close();
} catch (FileNotFoundException e) {
System.err.println("File not found: " + e);
}
}
/**
* Removes white space from the supplied string and returns the trimmed
* String.
*
* #param s String value to strip white space from.
* #return String stripped of white space.
*/
public String trimWhitespace(String s) {
String newString = "";
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != ' ') {
newString += s.charAt(i);
}
}
return newString;
}
/**
* Returns the sprite facing the direction supplied.
*
* #param facing String value containing 1 of 4 cardinal directions to make
* the sprite face.
* #return Image of the sprite facing the proper direction.
*/
private Image printGuy(String facing) {
if (facing.equals("south")) { // draw sprite facing south
if (step) {
step = false;
return south1.getImage();
} else {
step = true;
return south2.getImage();
}
} else if (facing.equals("north")) { // draw sprite facing north
if (step) {
step = false;
return north1.getImage();
} else {
step = true;
return north2.getImage();
}
} else if (facing.equals("east")) { // draw sprite facing east
if (step) {
step = false;
return east1.getImage();
} else {
step = true;
return east2.getImage();
}
} else if (facing.equals("west")) { // draw sprite facing west
if (step) {
step = false;
return west1.getImage();
} else {
step = true;
return west2.getImage();
}
}
return null;
}
/**
* Prints the Maze using sprites.
*
* #return BufferedImage rendition of the maze.
*/
public BufferedImage printMaze() {
BufferedImage mi = new BufferedImage(width * SPRITE_WIDTH, height * SPRITE_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g2 = mi.createGraphics();
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (maze[i][j] == '#') { // draw wall
g2.drawImage(wall1.getImage(), j * SPRITE_WIDTH, i * SPRITE_HEIGHT, null, null);
} else if (maze[i][j] == '%') { // draw wall
g2.drawImage(wall2.getImage(), j * SPRITE_WIDTH, i * SPRITE_HEIGHT, null, null);
} else if (maze[i][j] == '.' || maze[i][j] == 'X') { // draw ground
g2.drawImage(ground.getImage(), j * SPRITE_WIDTH, i * SPRITE_HEIGHT, null, null);
} else if (maze[i][j] == 'F') { // draw finish
g2.drawImage(finish.getImage(), j * SPRITE_WIDTH, i * SPRITE_HEIGHT, null, null);
}
}
}
return mi;
}
public void writeToFile() throws FileNotFoundException {
PrintWriter printWriter = new PrintWriter("steps.txt");
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
printWriter.print(steps[i][j] + " ");
}
printWriter.println();
}
printWriter.close();
}
public void closingMethod() {
long endTime = currentTime - startTime;
long finalTime = endTime / 100;
System.exit(0);
}
private class TimerHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
timerFired = true;
}
}
private class WindowHandler extends WindowAdapter {
public void windowClosing(WindowEvent e) {
removeAll();
closingMethod();
System.exit(0);
}
}
}
Essentially what you did was to solve the maze using DFS with a fixed exploration rule (right hand). The info you should save is the number of times you stepped on a square. when you hit a dead end you will be going back to the intersection to try another branch.
So on the second solving, when you find an intersection with a score > 1, you should modify the explore rule to avoid branches that have score > 1 (1 means u never had to come back == previous solution path, 2 (or more) means you had to come back after a dead-end (or a few)). Hope that made sense.
I have a program that creates a Grid and rearranges it by drag-and-droping, first of all everything is functional BUT not the way I wanted it. The must common rearrange is this, you drag an object and when you drop it falls into that position moving all the rest forward until they find the empty space, what I want is more simple; I want the objects to switch with the one that's in the position you dropped it. This is the code of the adapter:
#SuppressLint("WrongCall")
public class DragGridView extends ViewGroup implements View.OnTouchListener,
View.OnClickListener, View.OnLongClickListener {
public static float childRatio = .9f;
protected int colCount, childSize, padding, dpi, scroll = 0;
protected float lastDelta = 0;
protected Handler handler = new Handler();
protected int dragged = -1, lastX = -1, lastY = -1, lastTarget = -1;
protected boolean enabled = true, touching = false;
public static int animT = 150;
protected ArrayList<Integer> newPositions = new ArrayList<Integer>();
protected OnRearrangeListener onRearrangeListener;
protected OnClickListener secondaryOnClickListener;
private OnItemClickListener onItemClickListener;
public interface OnRearrangeListener {
public abstract void onRearrange(int oldIndex, int newIndex);
}
public DragGridView(Context context, AttributeSet attrs) {
super(context, attrs);
setListeners();
handler.removeCallbacks(updateTask);
handler.postAtTime(updateTask, SystemClock.uptimeMillis() + 500);
setChildrenDrawingOrderEnabled(true);
DisplayMetrics metrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
dpi = metrics.densityDpi;
}
protected void setListeners() {
setOnTouchListener(this);
super.setOnClickListener(this);
setOnLongClickListener(this);
}
#Override
public void setOnClickListener(OnClickListener l) {
secondaryOnClickListener = l;
}
protected Runnable updateTask = new Runnable() {
public void run() {
if (dragged != -1) {
if (lastY < padding * 3 && scroll > 0)
scroll -= 20;
else if (lastY > getBottom() - getTop() - (padding * 3)
&& scroll < getMaxScroll())
scroll += 20;
} else if (lastDelta != 0 && !touching) {
scroll += lastDelta;
lastDelta *= .9;
if (Math.abs(lastDelta) < .25)
lastDelta = 0;
}
clampScroll();
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
handler.postDelayed(this, 25);
}
};
#Override
public void addView(View child) {
super.addView(child);
newPositions.add(-1);
};
#Override
public void removeViewAt(int index) {
super.removeViewAt(index);
newPositions.remove(index);
};
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// compute width of view, in dp
float w = (r - l) / (dpi / 160f);
colCount = 2;
int sub = 240;
w -= 280;
while (w > 0) {
colCount++;
w -= sub;
sub += 40;
}
childSize = (r - l) / colCount;
childSize = Math.round(childSize * childRatio);
padding = ((r - l) - (childSize * colCount)) / (colCount + 1);
for (int i = 0; i < getChildCount(); i++)
if (i != dragged) {
Point xy = getCoorFromIndex(i);
getChildAt(i).layout(xy.x, xy.y, xy.x + childSize,
xy.y + childSize);
}
}
#Override
protected int getChildDrawingOrder(int childCount, int i) {
if (dragged == -1)
return i;
else if (i == childCount - 1)
return dragged;
else if (i >= dragged)
return i + 1;
return i;
}
public int getIndexFromCoor(int x, int y) {
int col = getColOrRowFromCoor(x), row = getColOrRowFromCoor(y + scroll);
if (col == -1 || row == -1)
return -1;
int index = row * colCount + col;
if (index >= getChildCount())
return -1;
return index;
}
protected int getColOrRowFromCoor(int coor) {
coor -= padding;
for (int i = 0; coor > 0; i++) {
if (coor < childSize)
return i;
coor -= (childSize + padding);
}
return -1;
}
protected int getTargetFromCoor(int x, int y) {
if (getColOrRowFromCoor(y + scroll) == -1)
return -1;
int leftPos = getIndexFromCoor(x - (childSize / 4), y);
int rightPos = getIndexFromCoor(x + (childSize / 4), y);
if (leftPos == -1 && rightPos == -1)
return -1;
if (leftPos == rightPos)
return -1;
int target = -1;
if (rightPos > -1)
target = rightPos;
else if (leftPos > -1)
target = leftPos + 1;
if (dragged < target)
return target - 1;
return target;
}
protected Point getCoorFromIndex(int index) {
int col = index % colCount;
int row = index / colCount;
return new Point(padding + (childSize + padding) * col, padding
+ (childSize + padding) * row - scroll);
}
public int getIndexOf(View child) {
for (int i = 0; i < getChildCount(); i++)
if (getChildAt(i) == child)
return i;
return -1;
}
public void onClick(View view) {
if (enabled) {
if (secondaryOnClickListener != null)
secondaryOnClickListener.onClick(view);
if (onItemClickListener != null && getLastIndex() != -1)
onItemClickListener.onItemClick(null,
getChildAt(getLastIndex()), getLastIndex(),
getLastIndex() / colCount);
}
}
public boolean onLongClick(View view) {
if (!enabled)
return false;
int index = getLastIndex();
if (index != -1) {
dragged = index;
animateDragged();
return true;
}
return false;
}
#SuppressLint("WrongCall")
public boolean onTouch(View view, MotionEvent event) {
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
enabled = true;
lastX = (int) event.getX();
lastY = (int) event.getY();
touching = true;
break;
case MotionEvent.ACTION_MOVE:
int delta = lastY - (int) event.getY();
if (dragged != -1) {
// change draw location of dragged visual
int x = (int) event.getX(), y = (int) event.getY();
int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);
getChildAt(dragged).layout(l, t, l + (childSize * 3 / 2),
t + (childSize * 3 / 2));
// check for new target hover
int target = getTargetFromCoor(x, y);
if (lastTarget != target) {
if (target != -1) {
animateGap(target);
lastTarget = target;
}
}
} else {
scroll += delta;
clampScroll();
if (Math.abs(delta) > 2)
enabled = false;
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
}
lastX = (int) event.getX();
lastY = (int) event.getY();
lastDelta = delta;
break;
case MotionEvent.ACTION_UP:
if (dragged != -1) {
View v = getChildAt(dragged);
if (lastTarget != -1)
reorderChildren();
else {
Point xy = getCoorFromIndex(dragged);
v.layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);
}
v.clearAnimation();
if (v instanceof ImageView)
((ImageView) v).setAlpha(255);
lastTarget = -1;
dragged = -1;
}
touching = false;
break;
}
if (dragged != -1)
return true;
return false;
}
protected void animateDragged() {
View v = getChildAt(dragged);
int x = getCoorFromIndex(dragged).x + childSize / 2, y = getCoorFromIndex(dragged).y
+ childSize / 2;
int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);
v.layout(l, t, l + (childSize * 3 / 2), t + (childSize * 3 / 2));
AnimationSet animSet = new AnimationSet(true);
ScaleAnimation scale = new ScaleAnimation(.667f, 1, .667f, 1,
childSize * 3 / 4, childSize * 3 / 4);
scale.setDuration(animT);
AlphaAnimation alpha = new AlphaAnimation(1, .5f);
alpha.setDuration(animT);
animSet.addAnimation(scale);
animSet.addAnimation(alpha);
animSet.setFillEnabled(true);
animSet.setFillAfter(true);
v.clearAnimation();
v.startAnimation(animSet);
}
protected void animateGap(int target) {
for (int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
if (i == dragged)
continue;
int newPos = i;
if (dragged < target && i >= dragged + 1 && i <= target)
newPos--;
else if (target < dragged && i >= target && i < dragged)
newPos++;
int oldPos = i;
if (newPositions.get(i) != -1)
oldPos = newPositions.get(i);
if (oldPos == newPos)
continue;
Point oldXY = getCoorFromIndex(oldPos);
Point newXY = getCoorFromIndex(newPos);
Point oldOffset = new Point(oldXY.x - v.getLeft(), oldXY.y
- v.getTop());
Point newOffset = new Point(newXY.x - v.getLeft(), newXY.y
- v.getTop());
TranslateAnimation translate = new TranslateAnimation(
Animation.ABSOLUTE, oldOffset.x, Animation.ABSOLUTE,
newOffset.x, Animation.ABSOLUTE, oldOffset.y,
Animation.ABSOLUTE, newOffset.y);
translate.setDuration(animT);
translate.setFillEnabled(true);
translate.setFillAfter(true);
v.clearAnimation();
v.startAnimation(translate);
newPositions.set(i, newPos);
}
}
protected void reorderChildren() {
if (onRearrangeListener != null)
onRearrangeListener.onRearrange(dragged, lastTarget);
ArrayList<View> children = new ArrayList<View>();
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).clearAnimation();
children.add(getChildAt(i));
}
removeAllViews();
while (dragged != lastTarget)
if (lastTarget == children.size())
{
children.add(children.remove(dragged));
dragged = lastTarget;
} else if (dragged < lastTarget)
{
Collections.swap(children, dragged, dragged + 1);
dragged++;
} else if (dragged > lastTarget)
{
Collections.swap(children, dragged, dragged - 1);
dragged--;
}
for (int i = 0; i < children.size(); i++) {
newPositions.set(i, -1);
addView(children.get(i));
}
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
}
#SuppressLint("WrongCall")
public void scrollToTop() {
scroll = 0;
}
public void scrollToBottom() {
scroll = Integer.MAX_VALUE;
clampScroll();
}
protected void clampScroll() {
int stretch = 3, overreach = getHeight() / 2;
int max = getMaxScroll();
max = Math.max(max, 0);
if (scroll < -overreach) {
scroll = -overreach;
lastDelta = 0;
} else if (scroll > max + overreach) {
scroll = max + overreach;
lastDelta = 0;
} else if (scroll < 0) {
if (scroll >= -stretch)
scroll = 0;
else if (!touching)
scroll -= scroll / stretch;
} else if (scroll > max) {
if (scroll <= max + stretch)
scroll = max;
else if (!touching)
scroll += (max - scroll) / stretch;
}
}
protected int getMaxScroll() {
int rowCount = (int) Math.ceil((double) getChildCount() / colCount), max = rowCount
* childSize + (rowCount + 1) * padding - getHeight();
return max;
}
public int getLastIndex() {
return getIndexFromCoor(lastX, lastY);
}
public void setOnRearrangeListener(OnRearrangeListener l) {
this.onRearrangeListener = l;
}
public void setOnItemClickListener(OnItemClickListener l) {
this.onItemClickListener = l;
}
}
The Methods I think I have to change are AnimateGap and reorderChildren, but don't know how to do it exactly.
My application has a SashForm with two children. I want the left child to stay the same size when the window is resized. I want the same thing Eclipse does with the Package Explorer and the main editor. When you resize the window only the text editor changes size. However, the Package Explorer is still resizeable by the sash.
I tried using the following
sashForm.addControlListener(new ControlAdapter() {
#Override
public void controlResized(ControlEvent e) {
int width = sashForm.getClientArea().width;
int[] weights = sashForm.getWeights();
weights[1] = width - weights[0];
sashForm.setWeights(weights);
}
});
The problem is the width of the left size either shrinks to 0 or expands too much. It looks like the weights are updated before this is called or something.
If I set weights[0] equal to some constant it does what I want.
I managed to get an example running that should give you an idea how to solve your problem. The thing is, that the SashForm uses weights rather than pixels. So you have to compute the percentage the left child has to occupy based on the parent size and assign the rest to the right child.
In my code example, you can specify the width of the left child and set a minimal size for the right child, such that the SashForm will always show both.
private static final int MIN_WIDTH_LEFT = 100;
private static final int MIN_WIDTH_RIGHT = 50;
public static void main(String[] args)
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final SashForm form = new SashForm(shell, SWT.HORIZONTAL);
Button button = new Button(form, SWT.PUSH);
button.setText("Left");
Button buttonR = new Button(form, SWT.PUSH);
buttonR.setText("Right");
form.setWeights(new int[] {1, 2});
shell.addListener(SWT.Resize, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
int width = shell.getClientArea().width;
int[] weights = form.getWeights();
if(width >= MIN_WIDTH_LEFT + MIN_WIDTH_RIGHT)
{
weights[0] = 1000000 * MIN_WIDTH_LEFT / width;
weights[1] = 1000000 - weights[0];
}
else
{
weights[0] = 1000000 * MIN_WIDTH_LEFT / (MIN_WIDTH_LEFT + MIN_WIDTH_RIGHT);
weights[1] = 1000000 * MIN_WIDTH_RIGHT / (MIN_WIDTH_LEFT + MIN_WIDTH_RIGHT);
}
System.out.println(width + " " + Arrays.toString(weights));
form.setWeights(weights);
}
});
shell.pack();
shell.setSize(600, 400);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
This is what it looks like:
Startup:
After resizing:
When decreasing the window size until it is too small to show both minimal sizes:
As you can see in this case, the minimal size for the left child is ignored to still be able to show both childs.
This is the best solution I could come up with.
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
public class Main {
private static int leftWidth, oldWeight;
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
shell.setSize(600, 400);
final SashForm form = new SashForm(shell, SWT.HORIZONTAL);
final Button button = new Button(form, SWT.PUSH);
button.setText("Left");
button.addListener(SWT.Resize, new Listener() {
#Override
public void handleEvent(Event arg0) {
int[] weights = form.getWeights();
// oldWeights is used to distinguish between a window resize and
// a sash move
if (oldWeight != weights[0]) {
System.out.println("Weights changed!");
oldWeight = weights[0];
leftWidth = (int) Math.round((double) form.getClientArea().width
* (double) weights[0]
/ (double) (weights[0] + weights[1]));
}
}
});
Button buttonR = new Button(form, SWT.PUSH);
buttonR.setText("Right");
form.setWeights(new int[] { 200, 800 });
leftWidth = 200;
form.addListener(SWT.Resize, new Listener() {
#Override
public void handleEvent(Event arg0) {
int width = form.getClientArea().width;
int[] weights = form.getWeights();
double perChange = (double) leftWidth / (double) width;
weights[0] = (int) (perChange * 1000.0);
weights[1] = 1000 - weights[0];
// oldWeights must be set before form.setWeights
oldWeight = weights[0];
form.setWeights(weights);
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
The sash jumps around about 1px when the window is resized due to rounding issues, but it seems to do what I want.
This is a very hacky solution and I would like to know if there is a better one. It also crashes if you make the window smaller than the left button, but that is easy to fix.
Have to rewrite SashForm to get this behavior. new SashForm(Composite parent, int style) is old behavior; new SashForm(Composite parent, int style, false) uses widths/heights specified in pixels.
Not tested with more than two Composite children of the SashForm, and odd behavior if you don't setLength when using new behavior, but will not break existing uses of SashForm
e.g.:
public static void main(String[] args)
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final SashForm form = new SashForm(shell, SWT.HORIZONTAL);
Button button = new Button(form, SWT.PUSH);
button.setText("Left");
Button buttonR = new Button(form, SWT.PUSH);
buttonR.setText("Right");
form.setLengths(new int[] { 250, 25 });
shell.pack();
shell.setSize(600, 400);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
First button will default to 250 pixels, second the remainder shell
SashForm.java:
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;
public class SashForm extends Composite {
/**
* The width of all sashes in the form.
*/
public int SASH_WIDTH = 3;
int sashStyle;
final private boolean weighted;
Sash[] sashes = new Sash[0];
// Remember background and foreground
// colors to determine whether to set
// sashes to the default color (null) or
// a specific color
Color background = null;
Color foreground = null;
Control[] controls = new Control[0];
Control maxControl = null;
Listener sashListener;
static final int DRAG_MINIMUM = 20;
public SashForm(Composite parent, int style) {
super(parent, checkStyle(style));
super.setLayout(new SashFormLayout());
sashStyle = ((style & SWT.VERTICAL) != 0) ? SWT.HORIZONTAL : SWT.VERTICAL;
if ((style & SWT.BORDER) != 0) sashStyle |= SWT.BORDER;
if ((style & SWT.SMOOTH) != 0) sashStyle |= SWT.SMOOTH;
sashListener = new Listener() {
public void handleEvent(Event e) {
onDragSash(e);
}
};
weighted = true;
}
public SashForm(Composite parent, int style, boolean weighted) {
super(parent, checkStyle(style));
super.setLayout(new SashFormLayout());
sashStyle = ((style & SWT.VERTICAL) != 0) ? SWT.HORIZONTAL : SWT.VERTICAL;
if ((style & SWT.BORDER) != 0) sashStyle |= SWT.BORDER;
if ((style & SWT.SMOOTH) != 0) sashStyle |= SWT.SMOOTH;
sashListener = new Listener() {
public void handleEvent(Event e) {
onDragSash(e);
}
};
this.weighted = weighted;
}
static int checkStyle (int style) {
int mask = SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
return style & mask;
}
Sash createSash() {
Sash sash = new Sash(this, sashStyle);
sash.setBackground(background);
sash.setForeground(foreground);
sash.setToolTipText(getToolTipText());
sash.addListener(SWT.Selection, sashListener);
return sash;
}
#Override
public int getOrientation() {
//checkWidget();
return (sashStyle & SWT.VERTICAL) != 0 ? SWT.HORIZONTAL : SWT.VERTICAL;
}
/**
* Returns the width of the sashes when the controls in the SashForm are
* laid out.
*
* #return the width of the sashes
*
* #exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* #since 3.4
*/
public int getSashWidth() {
checkWidget();
return SASH_WIDTH;
}
#Override
public int getStyle() {
int style = super.getStyle();
style |= getOrientation() == SWT.VERTICAL ? SWT.VERTICAL : SWT.HORIZONTAL;
if ((sashStyle & SWT.SMOOTH) != 0) style |= SWT.SMOOTH;
return style;
}
/**
* Answer the control that currently is maximized in the SashForm.
* This value may be null.
*
* #return the control that currently is maximized or null
*/
public Control getMaximizedControl(){
//checkWidget();
return this.maxControl;
}
public int[] getWeights() {
checkWidget();
Control[] cArray = getControls(false);
int[] ratios = new int[cArray.length];
for (int i = 0; i < cArray.length; i++) {
Object data = cArray[i].getLayoutData();
if (data != null && data instanceof SashFormData) {
ratios[i] = (int)(((SashFormData)data).weight * 1000 >> 16);
} else {
ratios[i] = 200;
}
}
return ratios;
}
Control[] getControls(boolean onlyVisible) {
Control[] children = getChildren();
Control[] result = new Control[0];
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Sash) continue;
if (onlyVisible && !children[i].getVisible()) continue;
Control[] newResult = new Control[result.length + 1];
System.arraycopy(result, 0, newResult, 0, result.length);
newResult[result.length] = children[i];
result = newResult;
}
return result;
}
boolean getWeighted() {
return weighted;
}
void onDragSash(Event event) {
Sash sash = (Sash)event.widget;
int sashIndex = -1;
for (int i= 0; i < sashes.length; i++) {
if (sashes[i] == sash) {
sashIndex = i;
break;
}
}
if (sashIndex == -1) return;
Control c1 = controls[sashIndex];
Control c2 = controls[sashIndex + 1];
Rectangle b1 = c1.getBounds();
Rectangle b2 = c2.getBounds();
Rectangle sashBounds = sash.getBounds();
Rectangle area = getClientArea();
boolean correction = false;
if (getOrientation() == SWT.HORIZONTAL) {
correction = b1.width < DRAG_MINIMUM || b2.width < DRAG_MINIMUM;
int totalWidth = b2.x + b2.width - b1.x;
int shift = event.x - sashBounds.x;
b1.width += shift;
b2.x += shift;
b2.width -= shift;
if (b1.width < DRAG_MINIMUM) {
b1.width = DRAG_MINIMUM;
b2.x = b1.x + b1.width + sashBounds.width;
b2.width = totalWidth - b2.x;
event.x = b1.x + b1.width;
event.doit = false;
}
if (b2.width < DRAG_MINIMUM) {
b1.width = totalWidth - DRAG_MINIMUM - sashBounds.width;
b2.x = b1.x + b1.width + sashBounds.width;
b2.width = DRAG_MINIMUM;
event.x = b1.x + b1.width;
event.doit = false;
}
Object data1 = c1.getLayoutData();
if (data1 == null || !(data1 instanceof SashFormData)) {
data1 = new SashFormData();
c1.setLayoutData(data1);
}
Object data2 = c2.getLayoutData();
if (data2 == null || !(data2 instanceof SashFormData)) {
data2 = new SashFormData();
c2.setLayoutData(data2);
}
((SashFormData)data1).weight = (((long)b1.width << 16) + area.width - 1) / area.width;
((SashFormData)data1).length = b1.width;
((SashFormData)data2).weight = (((long)b2.width << 16) + area.width - 1) / area.width;
((SashFormData)data2).length = b2.width;
} else {
correction = b1.height < DRAG_MINIMUM || b2.height < DRAG_MINIMUM;
int totalHeight = b2.y + b2.height - b1.y;
int shift = event.y - sashBounds.y;
b1.height += shift;
b2.y += shift;
b2.height -= shift;
if (b1.height < DRAG_MINIMUM) {
b1.height = DRAG_MINIMUM;
b2.y = b1.y + b1.height + sashBounds.height;
b2.height = totalHeight - b2.y;
event.y = b1.y + b1.height;
event.doit = false;
}
if (b2.height < DRAG_MINIMUM) {
b1.height = totalHeight - DRAG_MINIMUM - sashBounds.height;
b2.y = b1.y + b1.height + sashBounds.height;
b2.height = DRAG_MINIMUM;
event.y = b1.y + b1.height;
event.doit = false;
}
Object data1 = c1.getLayoutData();
if (data1 == null || !(data1 instanceof SashFormData)) {
data1 = new SashFormData();
c1.setLayoutData(data1);
}
Object data2 = c2.getLayoutData();
if (data2 == null || !(data2 instanceof SashFormData)) {
data2 = new SashFormData();
c2.setLayoutData(data2);
}
((SashFormData)data1).weight = (((long)b1.height << 16) + area.height - 1) / area.height;
((SashFormData)data2).weight = (((long)b2.height << 16) + area.height - 1) / area.height;
}
if (correction || (event.doit && event.detail != SWT.DRAG)) {
c1.setBounds(b1);
sash.setBounds(event.x, event.y, event.width, event.height);
c2.setBounds(b2);
}
}
#Override
public void setOrientation(int orientation) {
checkWidget();
if (orientation == SWT.RIGHT_TO_LEFT || orientation == SWT.LEFT_TO_RIGHT) {
super.setOrientation(orientation);
return;
}
if (getOrientation() == orientation) return;
if (orientation != SWT.HORIZONTAL && orientation != SWT.VERTICAL) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
sashStyle &= ~(SWT.HORIZONTAL | SWT.VERTICAL);
sashStyle |= orientation == SWT.VERTICAL ? SWT.HORIZONTAL : SWT.VERTICAL;
for (int i = 0; i < sashes.length; i++) {
sashes[i].dispose();
sashes[i] = createSash();
}
layout(false);
}
#Override
public void setBackground (Color color) {
super.setBackground(color);
background = color;
for (int i = 0; i < sashes.length; i++) {
sashes[i].setBackground(background);
}
}
#Override
public void setForeground (Color color) {
super.setForeground(color);
foreground = color;
for (int i = 0; i < sashes.length; i++) {
sashes[i].setForeground(foreground);
}
}
#Override
public void setLayout (Layout layout) {
checkWidget();
return;
}
public void setMaximizedControl(Control control){
checkWidget();
if (control == null) {
if (maxControl != null) {
this.maxControl = null;
layout(false);
for (int i= 0; i < sashes.length; i++){
sashes[i].setVisible(true);
}
}
return;
}
for (int i= 0; i < sashes.length; i++){
sashes[i].setVisible(false);
}
maxControl = control;
layout(false);
}
public void setSashWidth(int width) {
checkWidget();
if (SASH_WIDTH == width) return;
SASH_WIDTH = width;
layout(false);
}
#Override
public void setToolTipText(String string) {
super.setToolTipText(string);
for (int i = 0; i < sashes.length; i++) {
sashes[i].setToolTipText(string);
}
}
public void setWeights(int[] weights) {
checkWidget();
Control[] cArray = getControls(false);
if (weights == null || weights.length != cArray.length) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
int total = 0;
for (int i = 0; i < weights.length; i++) {
if (weights[i] < 0) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
total += weights[i];
}
if (total == 0) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
for (int i = 0; i < cArray.length; i++) {
Object data = cArray[i].getLayoutData();
if (data == null || !(data instanceof SashFormData)) {
data = new SashFormData();
cArray[i].setLayoutData(data);
}
((SashFormData)data).weight = (((long)weights[i] << 16) + total - 1) / total;
}
layout(false);
}
public void setLengths(int[] lengths) {
checkWidget();
Control[] cArray = getControls(false);
if (lengths == null || lengths.length != cArray.length) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
int total = 0;
for (int i = 0; i < lengths.length; i++) {
if (lengths[i] < 0) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
total += lengths[i];
}
if (total == 0) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
for (int i = 0; i < cArray.length; i++) {
Object data = cArray[i].getLayoutData();
if (data == null || !(data instanceof SashFormData)) {
data = new SashFormData();
cArray[i].setLayoutData(data);
}
((SashFormData)data).length = lengths[i];
}
layout(false);
}
}
SashFormData.java:
class SashFormData {
long weight;
int length;
String getName () {
String string = getClass ().getName ();
int index = string.lastIndexOf ('.');
if (index == -1) return string;
return string.substring (index + 1, string.length ());
}
#Override
public String toString () {
return getName()+" {length="+length+", weight="+weight+"}"; //$NON-NLS-2$
}
}
SashFormLayout.java:
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
class SashFormLayout extends Layout {
#Override
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
SashForm sashForm = (SashForm)composite;
Control[] cArray = sashForm.getControls(true);
int width = 0;
int height = 0;
if (cArray.length == 0) {
if (wHint != SWT.DEFAULT) width = wHint;
if (hHint != SWT.DEFAULT) height = hHint;
return new Point(width, height);
}
// determine control sizes
boolean vertical = sashForm.getOrientation() == SWT.VERTICAL;
if (sashForm.getWeighted()) {
int maxIndex = 0;
int maxValue = 0;
for (int i = 0; i < cArray.length; i++) {
if (vertical) {
Point size = cArray[i].computeSize(wHint, SWT.DEFAULT, flushCache);
if (size.y > maxValue) {
maxIndex = i;
maxValue = size.y;
}
width = Math.max(width, size.x);
} else {
Point size = cArray[i].computeSize(SWT.DEFAULT, hHint, flushCache);
if (size.x > maxValue) {
maxIndex = i;
maxValue = size.x;
}
height = Math.max(height, size.y);
}
}
// get the ratios
long[] ratios = new long[cArray.length];
long total = 0;
for (int i = 0; i < cArray.length; i++) {
Object data = cArray[i].getLayoutData();
if (data != null && data instanceof SashFormData) {
ratios[i] = ((SashFormData)data).weight;
} else {
data = new SashFormData();
cArray[i].setLayoutData(data);
((SashFormData)data).weight = ratios[i] = ((200 << 16) + 999) / 1000;
}
total += ratios[i];
}
if (ratios[maxIndex] > 0) {
int sashwidth = sashForm.sashes.length > 0 ? sashForm.SASH_WIDTH + sashForm.sashes [0].getBorderWidth() * 2 : sashForm.SASH_WIDTH;
if (vertical) {
height += (int)(total * maxValue / ratios[maxIndex]) + (cArray.length - 1) * sashwidth;
} else {
width += (int)(total * maxValue / ratios[maxIndex]) + (cArray.length - 1) * sashwidth;
}
}
} else {
int maxIndex = 0;
int maxValue = 0;
for (int i = 0; i < cArray.length; i++) {
if (vertical) {
Point size = cArray[i].computeSize(wHint, SWT.DEFAULT, flushCache);
if (size.y > maxValue) {
maxIndex = i;
maxValue = size.y;
}
width = Math.max(width, size.x);
} else {
Point size = cArray[i].computeSize(SWT.DEFAULT, hHint, flushCache);
if (size.x > maxValue) {
maxIndex = i;
maxValue = size.x;
}
height = Math.max(height, size.y);
}
}
// get the lengths
int[] lengths = new int[cArray.length];
long total = 0;
for (int i = 0; i < cArray.length; i++) {
Object data = cArray[i].getLayoutData();
if (data != null && data instanceof SashFormData) {
lengths[i] = ((SashFormData)data).length;
} else {
data = new SashFormData();
cArray[i].setLayoutData(data);
((SashFormData)data).length = sashForm.getOrientation() == SWT.HORIZONTAL ? cArray[i].getSize().x : cArray[i].getSize().y;
}
total += lengths[i];
}
if (lengths[maxIndex] > 0) {
int sashwidth = sashForm.sashes.length > 0 ? sashForm.SASH_WIDTH + sashForm.sashes [0].getBorderWidth() * 2 : sashForm.SASH_WIDTH;
if (vertical) {
height += total + (cArray.length - 1) * sashwidth;
} else {
width += total + (cArray.length - 1) * sashwidth;
}
}
}
width += sashForm.getBorderWidth()*2;
height += sashForm.getBorderWidth()*2;
if (wHint != SWT.DEFAULT) width = wHint;
if (hHint != SWT.DEFAULT) height = hHint;
return new Point(width, height);
}
#Override
protected boolean flushCache(Control control) {
return true;
}
#Override
protected void layout(Composite composite, boolean flushCache) {
SashForm sashForm = (SashForm)composite;
Rectangle area = sashForm.getClientArea();
if (area.width <= 1 || area.height <= 1) return;
Control[] newControls = sashForm.getControls(true);
if (sashForm.controls.length == 0 && newControls.length == 0) return;
sashForm.controls = newControls;
Control[] controls = sashForm.controls;
if (sashForm.maxControl != null && !sashForm.maxControl.isDisposed()) {
for (int i= 0; i < controls.length; i++){
if (controls[i] != sashForm.maxControl) {
controls[i].setBounds(-200, -200, 0, 0);
} else {
controls[i].setBounds(area);
}
}
return;
}
// keep just the right number of sashes
if (sashForm.sashes.length < controls.length - 1) {
Sash[] newSashes = new Sash[controls.length - 1];
System.arraycopy(sashForm.sashes, 0, newSashes, 0, sashForm.sashes.length);
for (int i = sashForm.sashes.length; i < newSashes.length; i++) {
newSashes[i] = sashForm.createSash();
}
sashForm.sashes = newSashes;
}
if (sashForm.sashes.length > controls.length - 1) {
if (controls.length == 0) {
for (int i = 0; i < sashForm.sashes.length; i++) {
sashForm.sashes[i].dispose();
}
sashForm.sashes = new Sash[0];
} else {
Sash[] newSashes = new Sash[controls.length - 1];
System.arraycopy(sashForm.sashes, 0, newSashes, 0, newSashes.length);
for (int i = controls.length - 1; i < sashForm.sashes.length; i++) {
sashForm.sashes[i].dispose();
}
sashForm.sashes = newSashes;
}
}
if (controls.length == 0) return;
Sash[] sashes = sashForm.sashes;
if (sashForm.getWeighted()) {
// get the ratios
long[] ratios = new long[controls.length];
long total = 0;
for (int i = 0; i < controls.length; i++) {
Object data = controls[i].getLayoutData();
if (data != null && data instanceof SashFormData) {
ratios[i] = ((SashFormData)data).weight;
} else {
data = new SashFormData();
controls[i].setLayoutData(data);
((SashFormData)data).weight = ratios[i] = ((200 << 16) + 999) / 1000;
}
total += ratios[i];
}
int sashwidth = sashes.length > 0 ? sashForm.SASH_WIDTH + sashes [0].getBorderWidth() * 2 : sashForm.SASH_WIDTH;
if (sashForm.getOrientation() == SWT.HORIZONTAL) {
int width = (int)(ratios[0] * (area.width - sashes.length * sashwidth) / total);
int x = area.x;
controls[0].setBounds(x, area.y, width, area.height);
x += width;
for (int i = 1; i < controls.length - 1; i++) {
sashes[i - 1].setBounds(x, area.y, sashwidth, area.height);
x += sashwidth;
width = (int)(ratios[i] * (area.width - sashes.length * sashwidth) / total);
controls[i].setBounds(x, area.y, width, area.height);
x += width;
}
if (controls.length > 1) {
sashes[sashes.length - 1].setBounds(x, area.y, sashwidth, area.height);
x += sashwidth;
width = area.width - x;
controls[controls.length - 1].setBounds(x, area.y, width, area.height);
}
} else {
int height = (int)(ratios[0] * (area.height - sashes.length * sashwidth) / total);
int y = area.y;
controls[0].setBounds(area.x, y, area.width, height);
y += height;
for (int i = 1; i < controls.length - 1; i++) {
sashes[i - 1].setBounds(area.x, y, area.width, sashwidth);
y += sashwidth;
height = (int)(ratios[i] * (area.height - sashes.length * sashwidth) / total);
controls[i].setBounds(area.x, y, area.width, height);
y += height;
}
if (controls.length > 1) {
sashes[sashes.length - 1].setBounds(area.x, y, area.width, sashwidth);
y += sashwidth;
height = area.height - y;
controls[controls.length - 1].setBounds(area.x, y, area.width, height);
}
}
} else {
// get the lengths
int[] lengths = new int[controls.length];
for (int i = 0; i < controls.length; i++) {
Object data = controls[i].getLayoutData();
if (data != null && data instanceof SashFormData) {
lengths[i] = ((SashFormData)data).length;
} else {
data = new SashFormData();
controls[i].setLayoutData(data);
((SashFormData)data).length = sashForm.getOrientation() == SWT.HORIZONTAL ? controls[i].getSize().x : controls[i].getSize().y;
}
}
int sashwidth = sashes.length > 0 ? sashForm.SASH_WIDTH + sashes [0].getBorderWidth() * 2 : sashForm.SASH_WIDTH;
if (sashForm.getOrientation() == SWT.HORIZONTAL) {
int width = lengths[0];
int x = area.x;
controls[0].setBounds(x, area.y, width, area.height);
x += width;
for (int i = 1; i < controls.length - 1; i++) {
sashes[i - 1].setBounds(x, area.y, sashwidth, area.height);
x += sashwidth;
width = lengths[i];
controls[i].setBounds(x, area.y, width, area.height);
x += width;
}
if (controls.length > 1) {
sashes[sashes.length - 1].setBounds(x, area.y, sashwidth, area.height);
x += sashwidth;
width = area.width - x;
controls[controls.length - 1].setBounds(x, area.y, width, area.height);
}
} else {
int height = lengths[0];
int y = area.y;
controls[0].setBounds(area.x, y, area.width, height);
y += height;
for (int i = 1; i < controls.length - 1; i++) {
sashes[i - 1].setBounds(area.x, y, area.width, sashwidth);
y += sashwidth;
height = lengths[i];
controls[i].setBounds(area.x, y, area.width, height);
y += height;
}
if (controls.length > 1) {
sashes[sashes.length - 1].setBounds(area.x, y, area.width, sashwidth);
y += sashwidth;
height = area.height - y;
controls[controls.length - 1].setBounds(area.x, y, area.width, height);
}
}
}
}
}
how do I calculate the font size of a TextView so that always occupy a certain percentage of the screen?
now I spit it out:
.....
densityNormal = Float.parseFloat("1.0");
densitySub = Float.parseFloat("0.75");
densityIper = Float.parseFloat("1.5");
densityExtra = Float.parseFloat("2.0");
.....
textviewSample.setTextSize(getHeightPercentage(context,30));
.....
private float getHeightPercentage(Context context, int percentage) {
if (percentage > 0 && percentage < 100) {
float appHeight = context.getApplicationContext().getResources()
.getDisplayMetrics().heightPixels;
float appSPDensity = context.getApplicationContext().getResources()
.getDisplayMetrics().scaledDensity;
if (Float.compare(appSPDensity, densitySub) == 0) {
appHeight = appHeight + ((appHeight * 25) / 100);
} else if (Float.compare(appSPDensity, densityIper) == 0) {
appHeight = ((appHeight * 50) / 100) - appHeight;
} else if (Float.compare(appSPDensity, densityExtra) == 0) {
appHeight = ((appHeight * 200) / 100) - appHeight;
}
return new Float((appHeight * percentage) / 100);
} else
return -1;
}
but I can not integrate the different density of the screen,have you any suggestions?8y3