mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-71: Prepping for source release.
This commit is contained in:
parent
ddbfbfe198
commit
8201baef2b
2705 changed files with 305722 additions and 53 deletions
|
@ -0,0 +1,155 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import ghidra.util.datastruct.ListenerSet;
|
||||
|
||||
public class ExpanderArrowPanel extends JPanel {
|
||||
// TODO: Can I make this consistent with the UI LaF
|
||||
protected final static Polygon ARROW =
|
||||
new Polygon(new int[] { 5, -5, -5 }, new int[] { 0, -5, 5 }, 3);
|
||||
protected final static Dimension SIZE = new Dimension(16, 16);
|
||||
protected final static int ANIM_MILLIS = 80;
|
||||
protected final static int FRAME_MILLIS = 30; // Approx 30 fps
|
||||
|
||||
private final ListenerSet<ExpanderArrowExpansionListener> listeners =
|
||||
new ListenerSet<>(ExpanderArrowExpansionListener.class);
|
||||
|
||||
private boolean expanded = false;
|
||||
|
||||
private double animTheta;
|
||||
private boolean animActive = false;
|
||||
private long animTimeEnd;
|
||||
private double animThetaEnd;
|
||||
private double animThetaOverTimeRate;
|
||||
|
||||
private final MouseListener mouseListener = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
toggle();
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
addMouseListener(mouseListener);
|
||||
}
|
||||
|
||||
public void addExpansionListener(ExpanderArrowExpansionListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeExpansionListener(ExpanderArrowExpansionListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
protected synchronized void animateTheta(double destTheta) {
|
||||
animTimeEnd = System.currentTimeMillis() + ANIM_MILLIS;
|
||||
animThetaEnd = destTheta;
|
||||
animThetaOverTimeRate = (destTheta - animTheta) / ANIM_MILLIS;
|
||||
animActive = true;
|
||||
scheduleNextFrame();
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
setExpanded(!expanded);
|
||||
}
|
||||
|
||||
protected boolean fireChanging(boolean newExpanded) {
|
||||
try {
|
||||
listeners.fire.changing(newExpanded);
|
||||
}
|
||||
catch (ExpanderArrowExpansionVetoException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void fireChanged() {
|
||||
listeners.fire.changed(expanded);
|
||||
}
|
||||
|
||||
public void setExpanded(boolean expanded) {
|
||||
if (this.expanded == expanded) {
|
||||
return;
|
||||
}
|
||||
if (!fireChanging(expanded)) {
|
||||
return;
|
||||
}
|
||||
double destTheta = expanded ? Math.PI / 2 : 0;
|
||||
animateTheta(destTheta);
|
||||
this.expanded = expanded;
|
||||
fireChanged();
|
||||
}
|
||||
|
||||
public boolean isExpanded() {
|
||||
return expanded;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.translate((double) SIZE.width / 2, (double) SIZE.height / 2);
|
||||
g2.rotate(animTheta);
|
||||
g2.fillPolygon(ARROW);
|
||||
|
||||
if (!animActive) {
|
||||
return;
|
||||
}
|
||||
long time = System.currentTimeMillis();
|
||||
double timeDiff = Math.max(0, animTimeEnd - time);
|
||||
if (timeDiff != 0) {
|
||||
double thetaDiff = timeDiff * animThetaOverTimeRate;
|
||||
animTheta = animThetaEnd - thetaDiff;
|
||||
scheduleNextFrame();
|
||||
return;
|
||||
}
|
||||
animActive = false;
|
||||
if (animTheta != animThetaEnd) {
|
||||
animTheta = animThetaEnd;
|
||||
scheduleNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
protected void scheduleNextFrame() {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
Thread.sleep(FRAME_MILLIS);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// Whatever. Render early.
|
||||
}
|
||||
repaint();
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue