From 75c2c0865434089a2a1330b4a2bf31c5bf98bd7b Mon Sep 17 00:00:00 2001 From: ghidragon <106987263+ghidragon@users.noreply.github.com> Date: Tue, 22 Nov 2022 15:58:28 -0500 Subject: [PATCH] GP-2865 created the mirror and flip icon modifiers. Also, updated undo/redo icons --- .../Framework/Docking/certification.manifest | 3 +- .../Docking/data/docking.theme.properties | 8 ++- .../resources/images/oxygen-edit-redo.png | Bin 0 -> 813 bytes .../src/main/resources/images/redo.png | Bin 727 -> 0 bytes .../src/main/resources/images/undo.png | Bin 692 -> 0 bytes .../main/java/generic/theme/IconModifier.java | 64 ++++++++++++++++-- .../java/resources/icons/ReflectedIcon.java | 62 +++++++++++++++++ .../java/generic/theme/IconModifierTest.java | 26 +++++-- 8 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 Ghidra/Framework/Docking/src/main/resources/images/oxygen-edit-redo.png delete mode 100644 Ghidra/Framework/Docking/src/main/resources/images/redo.png delete mode 100644 Ghidra/Framework/Docking/src/main/resources/images/undo.png create mode 100644 Ghidra/Framework/Generic/src/main/java/resources/icons/ReflectedIcon.java diff --git a/Ghidra/Framework/Docking/certification.manifest b/Ghidra/Framework/Docking/certification.manifest index bec96bb78a..63b6dea21f 100644 --- a/Ghidra/Framework/Docking/certification.manifest +++ b/Ghidra/Framework/Docking/certification.manifest @@ -85,6 +85,7 @@ src/main/resources/images/menu16.gif||GHIDRA||reviewed||END| src/main/resources/images/note-red.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/note.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/note.yellow.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| +src/main/resources/images/oxygen-edit-redo.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/page.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/page_code.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/page_excel.png||FAMFAMFAM Icons - CC 2.5||||END| @@ -92,7 +93,6 @@ src/main/resources/images/page_go.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/page_green.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/play.png||GHIDRA||||END| src/main/resources/images/preferences-system-windows.png||Tango Icons - Public Domain||||END| -src/main/resources/images/redo.png||Crystal Clear Icons - LGPL 2.1||||END| src/main/resources/images/software-update-available.png||Tango Icons - Public Domain|||tango icon set|END| src/main/resources/images/table.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/tag.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| @@ -100,7 +100,6 @@ src/main/resources/images/text_lowercase.png||FAMFAMFAM Icons - CC 2.5|||famfamf src/main/resources/images/textfield_rename.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/tip.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/trash-empty.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| -src/main/resources/images/undo.png||Crystal Clear Icons - LGPL 2.1||||END| src/main/resources/images/user-home.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/view-filter.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/warning.help.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| diff --git a/Ghidra/Framework/Docking/data/docking.theme.properties b/Ghidra/Framework/Docking/data/docking.theme.properties index e35755127a..6df04328ca 100644 --- a/Ghidra/Framework/Docking/data/docking.theme.properties +++ b/Ghidra/Framework/Docking/data/docking.theme.properties @@ -100,8 +100,12 @@ icon.subtract = list-remove.png icon.toggle.expand = expand.gif icon.toggle.collapse = collapse.gif -icon.undo = undo.png -icon.redo = redo.png +// the oxygen-edit-redo.png image is not centered vertically in its 16x16 icon. To center it we +// create an empty 16x16 base and then move down by 3 pixels +icon.undo = EMPTY_ICON{oxygen-edit-redo.png[mirror][move(0,3)]} +icon.redo = EMPTY_ICON{oxygen-edit-redo.png[move(0,3)]} + + icon.font = text_lowercase.png icon.rename = textfield_rename.png icon.check = check.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/oxygen-edit-redo.png b/Ghidra/Framework/Docking/src/main/resources/images/oxygen-edit-redo.png new file mode 100644 index 0000000000000000000000000000000000000000..9bfee2d1fa67bb64b67e71ed8adcbc9ff34d893e GIT binary patch literal 813 zcmV+|1JeA7P)-f{HKXqXOVUsMh>g{Fm38Z8Qn zsEFDGZQ8UhvUNerpno7-6$Ig?O-OCZAcUYVBpM^NPct)}nS1ZtxpU7wZ`0MvMd6|c z-o-iReV_ANoI}ivrO-8MC!*7qA@>qQmmn!jDPFpPe?QXt2KV#F#lAKGIuXP^yGsPkXpA4yj=jcrVLkFMzX$T>)v3>(A z0>~ho*mKZ;7WkFisNKFpkhrij*O{2|zQvJWJL8xw&4A{a>&!ajSBw!16Wh}5NEvoK zC|NED0G!F#E0YD`0s-*O|Ag{eN4u^cfG|`#|c1v ziImB6L9trVfmeq9Q3zc~B|y*%2^gG<()vw7mA-q* zn-jCqDiA;73-NFcz(CLT4OYO+hBg329O)`pX$59wphhVyj=2=fYSzViZCdz){8=N< zC(U@J5kR4Ys8$LEL>MptjEXsSqf9goz_BydL^&Uxrz_OLmv|IFGin?d+-yuWmB^1m zHF;>Bv50{JZnCBHbo1MP;Wz0EAXK54)Pxl|$9E2%NB?_cZp~4ajOyOqe zsAJ8W?5|$3;x`*V7+ z!;}k?6W5(tYya)d_Yj~Z=NXv5mVp6405LOI14$MJCk|nb4JPU)A_D9J3`ZUvX4wB> zKf_)AI}9&apEIaPsxUAMFbm$gam)1okN@j{CVyl20@U}1fdL?ZKweM=8gP_@pF{lj z@8665e*Ali;U5rkFzE5i@+T^|DzFPH2?Ld|FkISwiQ&br7db$UQyD%%yaEtFj12h< z>wwPD2RbVSC~%yCo#6)qD^T(sP~;nf1EW0S0i_}7%wPiaFDP1Ap{e2rByfPD*MV$f1_xktSOEFofEW~TazHEvRCyj43hx-=0RjkQ z00V{rzroS;mEkkPQJ`bp8H5=`z_$Mc;`czj66nTj3>m<*vk@SG@TWvphPyyp;(!{S z09g#+klzTz=NLMHa*IJq00IcN3mBmEKcG)PFgyT;fj7f*1~#D6cLUXB0a@U%0SF+% z20*-X0~k9h3@?G&{xie^)xBb1f#?AUAVx}aBR~LAoErfG3;^r{wM2?MBzph=002ov JPDHLkV1jHyC&K^$ diff --git a/Ghidra/Framework/Docking/src/main/resources/images/undo.png b/Ghidra/Framework/Docking/src/main/resources/images/undo.png deleted file mode 100644 index ee410a90484b51ab8da3bfe5f985b7e375b37e46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 692 zcmV;l0!#ggP)t+B5AZ7+51}6p;hDFRV%v>)yUNSs}!jF6(8UBd=5&3ud zpEko!h8^ILz+wPE0D%nH%D}-O^XK-TKfgZxV*0J{o8kB8-wZ#u|77@g<=-!c4-Cpc zP2Yf;4l?}0Fn|>xfLMUePiMFfbmVmgeukF}GZ?fOjkY!M1;020s0P!6Ld4}f6vG#w%ldu$>G(z>v{_CLWNp??V$2$k5L~dp(BRVTc7PN35I~F! zDbVEk5h;NFGAII*Yc0^Jp+HZt0Qn&KH^4Aj26W|2pvXP2T3~Vp2p~pEb0a_iQJfnA a0t^6r^QX$aM-V~)0000 overlayIconValues = null; /** @@ -47,12 +48,17 @@ public class IconModifier { * @param translation if non-null, translates an icon by this amount * @param rotation if non-null, the amount in degrees to rotate the icon * @param disabled if true, creates a disabled version of the icon + * @param mirror if true, the image will have its x values swapped (left to right) + * @param flip if true, the image will have its y values swapped (turned upside down) */ - public IconModifier(Dimension size, Point translation, Integer rotation, boolean disabled) { + public IconModifier(Dimension size, Point translation, Integer rotation, + boolean disabled, boolean mirror, boolean flip) { this.size = size; this.translation = translation; this.rotation = rotation; this.disabled = disabled; + this.mirror = mirror; + this.flip = flip; } private IconModifier() { @@ -92,6 +98,20 @@ public class IconModifier { disabled = true; } + /** + * Sets the modifier to flip the icon side to side + */ + public void setMirror() { + mirror = true; + } + + /** + * Sets the modifier to flip the icon side to side + */ + public void setFlip() { + flip = true; + } + /** * Modifies the given icon by the any of the modifiers set. * @param icon the icon to be modified @@ -107,8 +127,14 @@ public class IconModifier { if (disabled) { modified = ResourceManager.getDisabledIcon(modified); } + if (mirror) { + modified = new ReflectedIcon(modified, true); + } + if (flip) { + modified = new ReflectedIcon(modified, false); + } if (rotation != null) { - modified = new RotateIcon(icon, rotation); + modified = new RotateIcon(modified, rotation); } if (translation != null) { modified = new TranslateIcon(modified, translation.x, translation.y); @@ -132,6 +158,12 @@ public class IconModifier { if (size != null) { builder.append("[" + "size(" + size.width + "," + size.height + ")]"); } + if (mirror) { + builder.append("[mirror]"); + } + if (flip) { + builder.append("[flip]"); + } if (rotation != null) { builder.append("[rotate(" + rotation + ")]"); } @@ -195,6 +227,12 @@ public class IconModifier { else if (modifierString.startsWith("move")) { parseMoveModifier(modifier, modifierString); } + else if (modifierString.startsWith("mirror")) { + parseMirrorModifier(modifier, modifierString); + } + else if (modifierString.startsWith("flip")) { + parseFlipModifier(modifier, modifierString); + } else if (modifierString.startsWith("rotate")) { parseRotateModifier(modifier, modifierString); } @@ -228,7 +266,7 @@ public class IconModifier { private boolean hadModifications() { return size != null || translation != null || overlayIconValues != null || - rotation != null || disabled; + rotation != null || disabled || mirror || flip; } private static void parseDisabledModifier(IconModifier modifier, String modifierString) @@ -239,6 +277,22 @@ public class IconModifier { modifier.setDisabled(); } + private static void parseMirrorModifier(IconModifier modifier, String modifierString) + throws ParseException { + if (!modifierString.equals("mirror")) { + throw new ParseException("Illegal Icon modifier: " + modifier, 0); + } + modifier.setMirror(); + } + + private static void parseFlipModifier(IconModifier modifier, String modifierString) + throws ParseException { + if (!modifierString.equals("flip")) { + throw new ParseException("Illegal Icon modifier: " + modifier, 0); + } + modifier.setFlip(); + } + private static void parseRotateModifier(IconModifier modifier, String modifierString) throws ParseException { String argsString = modifierString.substring("rotate".length()); diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/ReflectedIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/ReflectedIcon.java new file mode 100644 index 0000000000..7259bd4bfe --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/ReflectedIcon.java @@ -0,0 +1,62 @@ +/* ### + * 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 resources.icons; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +/** + * {@link LazyImageIcon} that creates a reflected version of an icon. This creates a version of the + * icon which has had either its x values reflected (left to right) or its y values reflected + * (upside down) + */ +public class ReflectedIcon extends DerivedImageIcon { + + private boolean leftToRight; + + /** + * Construct a icon that is reflected either left to right or upside down. + * @param baseIcon base icon + * @param leftToRight true flips x values, false flips y values + */ + public ReflectedIcon(Icon baseIcon, boolean leftToRight) { + super(baseIcon); + this.leftToRight = leftToRight; + } + + @Override + protected ImageIcon createImageIcon() { + Icon sourceIcon = getSourceIcon(); + Image image = createImage(); + int width = sourceIcon.getIconWidth(); + int height = sourceIcon.getIconHeight(); + + BufferedImage flippedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = (Graphics2D) flippedImage.getGraphics(); + if (leftToRight) { + graphics.drawImage(image, width, 0, -width, height, null); + } + else { + graphics.drawImage(image, 0, height, width, -height, null); + } + graphics.dispose(); + return new ImageIcon(flippedImage, getFilename()); + } +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/IconModifierTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/IconModifierTest.java index 414d9b2332..60acf958a7 100644 --- a/Ghidra/Framework/Generic/src/test/java/generic/theme/IconModifierTest.java +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/IconModifierTest.java @@ -83,6 +83,20 @@ public class IconModifierTest { assertNotEquals(baseIcon, modifiedIcon); } + @Test + public void testMirrorModifier() throws Exception { + IconModifier modifier = IconModifier.parse("[mirror]"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertNotEquals(baseIcon, modifiedIcon); + } + + @Test + public void testFlipModifier() throws Exception { + IconModifier modifier = IconModifier.parse("[flip]"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertNotEquals(baseIcon, modifiedIcon); + } + @Test public void testOverlayIcon() throws Exception { IconModifier modifier = IconModifier.parse("{images/flag.png}"); @@ -179,11 +193,13 @@ public class IconModifierTest { @Test public void testGetSerializationString() { //@formatter:off - assertEquals("[size(5,9)]", new IconModifier(new Dimension(5,9), null, null, false).getSerializationString()); - assertEquals("[move(8,7)]", new IconModifier(null, new Point(8,7), null,false).getSerializationString()); - assertEquals("[disabled]", new IconModifier(null, null, null, true).getSerializationString()); - assertEquals("[size(5,0)][move(8,7)][disabled]", new IconModifier(new Dimension(5,0), new Point(8,7), null, true).getSerializationString()); - assertEquals("[rotate(90)]", new IconModifier(null, null, 90, false).getSerializationString()); + assertEquals("[size(5,9)]", new IconModifier(new Dimension(5,9), null, null, false, false, false).getSerializationString()); + assertEquals("[move(8,7)]", new IconModifier(null, new Point(8,7), null,false, false, false).getSerializationString()); + assertEquals("[disabled]", new IconModifier(null, null, null, true, false, false).getSerializationString()); + assertEquals("[size(5,0)][move(8,7)][disabled]", new IconModifier(new Dimension(5,0), new Point(8,7), null, true, false, false).getSerializationString()); + assertEquals("[rotate(90)]", new IconModifier(null, null, 90, false, false, false).getSerializationString()); + assertEquals("[mirror]", new IconModifier(null, null, null, false, true, false).getSerializationString()); + assertEquals("[flip]", new IconModifier(null, null, null, false, false, true).getSerializationString()); //@formatter:on } }