package com.swtjface.Ch6;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
public class RadialLayout extends Layout {
public RadialLayout() {
super();
}
/**
* 레이아웃이 필요로 하는 공간을 계산한다.
* @param composite 컨트롤을 넣을 객체
* @param wHint 너비
* @param hHint 높이
* @param flushCache 캐시된 값을 안전하게 사용할지 여부
* @return
*/
protected Point computeSize(Composite composite, int wHint, int hHint
, boolean flushCache) {
Point maxDimensions = calculateMaxDimensions(composite.getChildren());
int stepsPerHemisphere = stepsPerHemisphere(composite.getChildren().length);
int maxWidth = maxDimensions.x;
int maxHeight = maxDimensions.y;
int dimensionMultiplier = (stepsPerHemisphere + 1);
int controlWidth = maxWidth * dimensionMultiplier;
int controlHeight = maxHeight * dimensionMultiplier;
int diameter = Math.max(controlWidth, controlHeight);
Point preferredSize = new Point(diameter, diameter);
//레이아웃 크기 계산
if (wHint != SWT.DEFAULT) {
if (preferredSize.x > wHint) {
preferredSize.x = wHint;
}
}
if (hHint != SWT.DEFAULT) {
if (preferredSize.y > hHint) {
preferredSize.y = hHint;
}
}
return preferredSize;
}
/**
* 배치
*/
protected void layout(Composite composite, boolean flushCache) {
Point[] positions = calculateControlPositions(composite);
Control[] controls = composite.getChildren();
for (int i = 0; i < controls.length; i++) {
Point preferredSize = controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT);
controls[i].setBounds(positions[i].x, positions[i].y,
preferredSize.x, preferredSize.y);
}
}
/**
* 위젯 위치 설정
* @param composite
* @return
*/
private Point[] calculateControlPositions(Composite composite) {
//컨트롤 개수 설정
int controlCount = composite.getChildren().length;
//위젯 순서 설정
int stepsPerHemisphere = stepsPerHemisphere(controlCount);
Point[] positions = new Point[controlCount];
//최대 폭 설정
Point maxControlDimensions = calculateMaxDimensions(composite.getChildren());
int maxControlWidth = maxControlDimensions.x;
//위젯 배치 모양 설정 - 원
Rectangle clientArea = composite.getClientArea();
int smallestDimension = Math.min(clientArea.width, clientArea.height);
int radius = (smallestDimension / 2) - maxControlWidth;
Point center = new Point(clientArea.width / 2, clientArea.height / 2);
long radiusSquared = radius * radius;
int stepXDistance = calculateStepDistance(radius * 2, stepsPerHemisphere);
//부호변환 변수 (1:양수, -1:음수)
int signMultiplier = 1;
int x = -radius;
int y;
Control[] controls = composite.getChildren();
for (int i = 0; i < controlCount; i++) {
Point currSize = controls[i].getSize();
long xSquared = x * x;
int sqrRoot = (int) Math.sqrt(radiusSquared - xSquared);
y = signMultiplier * sqrRoot;
//원점이 아닌 원을 중심으로 좌표값을 반환한다.
int translatedX = x + center.x;
int translatedY = y + center.y;
positions[i] = new Point(translatedX - (currSize.x / 2),
translatedY - (currSize.y / 2));
x = x + (signMultiplier * stepXDistance);
//위쪽 반원은 완료됨. 아래쪽 반윈에 대해 수행.
// we've finished the upper hemisphere, now do the lower
if (x >= radius) {
x = radius - (x - radius);
signMultiplier = -1;
}
}
return positions;
}
/**
* 선호하는 가장 큰 값 구하기
* @param controls
* @return
*/
private Point calculateMaxDimensions(Control[] controls) {
Point maxes = new Point(0, 0);
for (int i = 0; i < controls.length; i++) {
Point controlSize = controls[i].computeSize(SWT.DEFAULT,
SWT.DEFAULT);
maxes.x = Math.max(maxes.x, controlSize.x);
maxes.y = Math.max(maxes.y, controlSize.y);
}
return maxes;
}
private int stepsPerHemisphere(int totalObjects) {
return (totalObjects / 2) - 1;
}
/**
* 위젯의 가로길이 구하기
* @param clientAreaDimensionSize
* @param stepCount
* @return
*/
private int calculateStepDistance(int clientAreaDimensionSize, int stepCount) {
return clientAreaDimensionSize / (stepCount + 1);
}
}
|