diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 61104f1..83d1fde 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,11 +2,20 @@ \ No newline at end of file diff --git a/Darcula.iml b/Darcula.iml index 82cf39c..7200644 100755 --- a/Darcula.iml +++ b/Darcula.iml @@ -8,6 +8,14 @@ + + + + + + + + + - - + \ No newline at end of file diff --git a/lib/annotations.jar b/lib/annotations.jar new file mode 100644 index 0000000..91a44ec Binary files /dev/null and b/lib/annotations.jar differ diff --git a/lib/iconloader.jar b/lib/iconloader.jar index a32173d..a161a57 100644 Binary files a/lib/iconloader.jar and b/lib/iconloader.jar differ diff --git a/src/com/bulenkov/darcula/util/Comparing.java b/src/com/bulenkov/darcula/util/Comparing.java new file mode 100644 index 0000000..093750d --- /dev/null +++ b/src/com/bulenkov/darcula/util/Comparing.java @@ -0,0 +1,214 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * 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 com.bulenkov.darcula.util; + +import java.util.*; + +public class Comparing { + private Comparing() { + } + + public static boolean equal(T arg1, T arg2) { + if (arg1 == arg2) return true; + if (arg1 == null || arg2 == null) { + return false; + } + if (arg1 instanceof Object[] && arg2 instanceof Object[]) { + Object[] arr1 = (Object[]) arg1; + Object[] arr2 = (Object[]) arg2; + return Arrays.equals(arr1, arr2); + } + if (arg1 instanceof CharSequence && arg2 instanceof CharSequence) { + return equal((CharSequence) arg1, (CharSequence) arg2, true); + } + return arg1.equals(arg2); + } + + public static boolean equal(T[] arr1, T[] arr2) { + if (arr1 == null || arr2 == null) { + return arr1 == arr2; + } + return Arrays.equals(arr1, arr2); + } + + public static boolean equal(CharSequence s1, CharSequence s2) { + return equal(s1, s2, true); + } + + public static boolean equal(String arg1, String arg2) { + return arg1 == null ? arg2 == null : arg1.equals(arg2); + } + + public static boolean equal(CharSequence s1, CharSequence s2, boolean caseSensitive) { + if (s1 == s2) return true; + if (s1 == null || s2 == null) return false; + + // Algorithm from String.regionMatches() + + if (s1.length() != s2.length()) return false; + int to = 0; + int po = 0; + int len = s1.length(); + + while (len-- > 0) { + char c1 = s1.charAt(to++); + char c2 = s2.charAt(po++); + if (c1 == c2) { + continue; + } + if (!caseSensitive && charsEqualIgnoreCase(c1, c2)) continue; + return false; + } + + return true; + } + + public static boolean charsEqualIgnoreCase(char a, char b) { + return a == b || toUpperCase(a) == toUpperCase(b) || toLowerCase(a) == toLowerCase(b); + } + public static char toUpperCase(char a) { + if (a < 'a') { + return a; + } + if (a <= 'z') { + return (char)(a + ('A' - 'a')); + } + return Character.toUpperCase(a); + } + + public static char toLowerCase(char a) { + if (a < 'A' || a >= 'a' && a <= 'z') { + return a; + } + + if (a <= 'Z') { + return (char)(a + ('a' - 'A')); + } + + return Character.toLowerCase(a); + } + + + public static boolean equal(String arg1, String arg2, boolean caseSensitive) { + if (arg1 == null || arg2 == null) { + return arg1 == arg2; + } else { + return caseSensitive ? arg1.equals(arg2) : arg1.equalsIgnoreCase(arg2); + } + } + + public static boolean strEqual(String arg1, String arg2) { + return strEqual(arg1, arg2, true); + } + + public static boolean strEqual(String arg1, String arg2, boolean caseSensitive) { + return equal(arg1 == null ? "" : arg1, arg2 == null ? "" : arg2, caseSensitive); + } + + public static boolean haveEqualElements(Collection a, Collection b) { + if (a.size() != b.size()) { + return false; + } + + Set aSet = new HashSet(a); + for (T t : b) { + if (!aSet.contains(t)) { + return false; + } + } + + return true; + } + + public static boolean haveEqualElements(T[] a, T[] b) { + if (a == null || b == null) { + return a == b; + } + + if (a.length != b.length) { + return false; + } + + Set aSet = new HashSet(Arrays.asList(a)); + for (T t : b) { + if (!aSet.contains(t)) { + return false; + } + } + + return true; + } + + @SuppressWarnings("MethodNamesDifferingOnlyByCase") + public static int hashcode(Object obj) { + return obj == null ? 0 : obj.hashCode(); + } + + public static int hashcode(Object obj1, Object obj2) { + return hashcode(obj1) ^ hashcode(obj2); + } + + public static int compare(byte o1, byte o2) { + return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; + } + + public static int compare(boolean o1, boolean o2) { + return o1 == o2 ? 0 : o1 ? 1 : -1; + } + + public static int compare(int o1, int o2) { + return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; + } + + public static int compare(long o1, long o2) { + return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; + } + + public static int compare(double o1, double o2) { + return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; + } + + public static int compare(byte[] o1, byte[] o2) { + if (o1 == o2) return 0; + if (o1 == null) return 1; + if (o2 == null) return -1; + + if (o1.length > o2.length) return 1; + if (o1.length < o2.length) return -1; + + for (int i = 0; i < o1.length; i++) { + if (o1[i] > o2[i]) return 1; + else if (o1[i] < o2[i]) return -1; + } + + return 0; + } + + public static > int compare(T o1, T o2) { + if (o1 == o2) return 0; + if (o1 == null) return -1; + if (o2 == null) return 1; + return o1.compareTo(o2); + } + + public static int compare(T o1, T o2, Comparator notNullComparator) { + if (o1 == o2) return 0; + if (o1 == null) return -1; + if (o2 == null) return 1; + return notNullComparator.compare(o1, o2); + } +} diff --git a/src/com/bulenkov/darcula/util/Registry.java b/src/com/bulenkov/darcula/util/Registry.java new file mode 100644 index 0000000..9382eff --- /dev/null +++ b/src/com/bulenkov/darcula/util/Registry.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * 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 com.bulenkov.darcula.util; + +/** + * @author Konstantin Bulenkov + */ +public class Registry { + public static boolean is(String key) { + return "true".equalsIgnoreCase(System.getProperty(key)); + } + + public static float getFloat(String key) { + try { + return Float.parseFloat(System.getProperty(key)); + } catch (Exception e) { + return 0f; + } + } +} diff --git a/src/com/intellij/util/ui/JBDimension.java b/src/com/intellij/util/ui/JBDimension.java new file mode 100644 index 0000000..401323f --- /dev/null +++ b/src/com/intellij/util/ui/JBDimension.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * 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 com.intellij.util.ui; + +import javax.swing.plaf.UIResource; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public class JBDimension extends Dimension { + public final float originalScale = JBUI.scale(1f); + + public JBDimension(int width, int height) { + super(scale(width), scale(height)); + } + + private static int scale(int size) { + return size == -1 ? -1 : JBUI.scale(size); + } + + public static JBDimension create(Dimension from) { + if (from instanceof JBDimension) { + return ((JBDimension)from); + } + return new JBDimension(from.width, from.height); + } + + public JBDimensionUIResource asUIResource() { + return new JBDimensionUIResource(this); + } + + public static class JBDimensionUIResource extends JBDimension implements UIResource { + public JBDimensionUIResource(JBDimension size) { + super(0, 0); + width = size.width; + height = size.height; + } + } + + public JBDimension withWidth(int width) { + JBDimension size = new JBDimension(0, 0); + size.width = scale(width); + size.height = height; + return size; + } + + public JBDimension withHeight(int height) { + JBDimension size = new JBDimension(0, 0); + size.width = width; + size.height = scale(height); + return size; + } +} diff --git a/src/com/intellij/util/ui/JBEmptyBorder.java b/src/com/intellij/util/ui/JBEmptyBorder.java new file mode 100644 index 0000000..63ec0bd --- /dev/null +++ b/src/com/intellij/util/ui/JBEmptyBorder.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * 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 com.intellij.util.ui; + +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.UIResource; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public class JBEmptyBorder extends EmptyBorder { + public JBEmptyBorder(int top, int left, int bottom, int right) { + super(JBUI.insets(top, left, bottom, right)); + } + + public JBEmptyBorder(Insets insets) { + super(JBUI.insets(insets)); + } + + public JBEmptyBorder(int offset) { + this(offset, offset, offset, offset); + } + + public JBEmptyBorderUIResource asUIResource() { + return new JBEmptyBorderUIResource(this); + } + + public static class JBEmptyBorderUIResource extends JBEmptyBorder implements UIResource { + public JBEmptyBorderUIResource(JBEmptyBorder border) { + super(0,0,0,0); + top = border.top; + left = border.left; + bottom = border.bottom; + right = border.right; + } + } +} diff --git a/src/com/intellij/util/ui/JBFont.java b/src/com/intellij/util/ui/JBFont.java new file mode 100644 index 0000000..3c3c113 --- /dev/null +++ b/src/com/intellij/util/ui/JBFont.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * 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 com.intellij.util.ui; + +import javax.swing.plaf.UIResource; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public class JBFont extends Font { + private JBFont(Font font) { + super(font); + } + + public static JBFont create(Font font) { + return create(font, true); + } + + public static JBFont create(Font font, boolean tryToScale) { + if (font instanceof JBFont) { + return ((JBFont)font); + } + Font scaled = font; + if (tryToScale) { + scaled = font.deriveFont(font.getSize() * JBUI.scale(1f)); + } + + if (font instanceof UIResource) { + return new JBFontUIResource(scaled); + } + + return new JBFont(scaled); + } + + public JBFont asBold() { + return deriveFont(BOLD, getSize()); + } + + public JBFont asItalic() { + return deriveFont(ITALIC, getSize()); + } + + public JBFont asPlain() { + return deriveFont(PLAIN, getSize()); + } + + @Override + public JBFont deriveFont(int style, float size) { + return create(super.deriveFont(style, size), false); + } + + @Override + public JBFont deriveFont(float size) { + return create(super.deriveFont(size), false); + } + + public JBFont biggerOn(float size) { + return deriveFont(getSize() + JBUI.scale(size)); + } + + public JBFont lessOn(float size) { + return deriveFont(getSize() - JBUI.scale(size)); + } + + private static class JBFontUIResource extends JBFont implements UIResource { + private JBFontUIResource(Font font) { + super(font); + } + } +} diff --git a/src/com/intellij/util/ui/JBInsets.java b/src/com/intellij/util/ui/JBInsets.java new file mode 100644 index 0000000..f3135b7 --- /dev/null +++ b/src/com/intellij/util/ui/JBInsets.java @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * 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 com.intellij.util.ui; + +import javax.swing.plaf.UIResource; +import java.awt.*; + +import static com.intellij.util.ui.JBUI.scale; + +/** + * @author Konstantin Bulenkov + */ +public class JBInsets extends Insets { + /** + * Creates and initializes a new Insets object with the + * specified top, left, bottom, and right insets. + * + * @param top the inset from the top. + * @param left the inset from the left. + * @param bottom the inset from the bottom. + * @param right the inset from the right. + */ + public JBInsets(int top, int left, int bottom, int right) { + super(scale(top), scale(left), scale(bottom), scale(right)); + } + + public int width() { + return left + right; + } + + public int height() { + return top + bottom; + } + + public static JBInsets create(Insets insets) { + if (insets instanceof JBInsets) { + JBInsets copy = new JBInsets(0, 0, 0, 0); + copy.top = insets.top; + copy.left = insets.left; + copy.bottom = insets.bottom; + copy.right = insets.right; + return copy; + } + return new JBInsets(insets.top, insets.left, insets.bottom, insets.right); + } + + public JBInsetsUIResource asUIResource() { + return new JBInsetsUIResource(this); + } + + public static class JBInsetsUIResource extends JBInsets implements UIResource { + public JBInsetsUIResource(JBInsets insets) { + super(0, 0, 0, 0); + top = insets.top; + left = insets.left; + bottom = insets.bottom; + right = insets.right; + } + } + + /** + * @param dimension the size to increase + * @param insets the insets to add + */ + public static void addTo(Dimension dimension, Insets insets) { + if (insets != null) { + dimension.width += insets.left + insets.right; + dimension.height += insets.top + insets.bottom; + } + } + + /** + * @param dimension the size to decrease + * @param insets the insets to remove + */ + public static void removeFrom(Dimension dimension, Insets insets) { + if (insets != null) { + dimension.width -= insets.left + insets.right; + dimension.height -= insets.top + insets.bottom; + } + } + + /** + * @param rectangle the size to increase and the location to move + * @param insets the insets to add + */ + public static void addTo(Rectangle rectangle, Insets insets) { + if (insets != null) { + rectangle.x -= insets.left; + rectangle.y -= insets.top; + rectangle.width += insets.left + insets.right; + rectangle.height += insets.top + insets.bottom; + } + } + + /** + * @param rectangle the size to decrease and the location to move + * @param insets the insets to remove + */ + public static void removeFrom(Rectangle rectangle, Insets insets) { + if (insets != null) { + rectangle.x += insets.left; + rectangle.y += insets.top; + rectangle.width -= insets.left + insets.right; + rectangle.height -= insets.top + insets.bottom; + } + } +} diff --git a/src/com/intellij/util/ui/JBUI.java b/src/com/intellij/util/ui/JBUI.java new file mode 100644 index 0000000..4c894a2 --- /dev/null +++ b/src/com/intellij/util/ui/JBUI.java @@ -0,0 +1,255 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * 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 com.intellij.util.ui; + +import com.bulenkov.iconloader.IconLoader; +import com.bulenkov.iconloader.util.EmptyIcon; +import com.bulenkov.iconloader.util.Pair; +import com.bulenkov.iconloader.util.SystemInfo; +import com.bulenkov.iconloader.util.UIUtil; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.plaf.UIResource; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public class JBUI { + private static float scaleFactor = 1.0f; + + static { + calculateScaleFactor(); + } + + private static void calculateScaleFactor() { + if (SystemInfo.isMac) { + scaleFactor = 1.0f; + return; + } + + if (System.getProperty("hidpi") != null && !"true".equalsIgnoreCase(System.getProperty("hidpi"))) { + scaleFactor = 1.0f; + return; + } + + UIUtil.initSystemFontData(); + Pair fdata = UIUtil.getSystemFontData(); + + int size; + if (fdata != null) { + size = fdata.getSecond(); + } else { + size = Fonts.label().getSize(); + } + setScaleFactor(size / UIUtil.DEF_SYSTEM_FONT_SIZE); + } + + public static void setScaleFactor(float scale) { + final String hidpi = System.getProperty("hidpi"); + if (hidpi != null && "false".equalsIgnoreCase(hidpi)) { + return; + } + + if (scale < 1.25f) scale = 1.0f; + else if (scale < 1.5f) scale = 1.25f; + else if (scale < 1.75f) scale = 1.5f; + else if (scale < 2f) scale = 1.75f; + else scale = 2.0f; + + if (SystemInfo.isLinux && scale == 1.25f) { + //Default UI font size for Unity and Gnome is 15. Scaling factor 1.25f works badly on Linux + scale = 1f; + } + if (scaleFactor == scale) { + return; + } + + scaleFactor = scale; + IconLoader.setScale(scale); + } + + public static int scale(int i) { + return Math.round(scaleFactor * i); + } + + public static int scaleFontSize(int fontSize) { + if (scaleFactor == 1.25f) return (int)(fontSize * 1.34f); + if (scaleFactor == 1.75f) return (int)(fontSize * 1.67f); + return scale(fontSize); + } + + public static JBDimension size(int width, int height) { + return new JBDimension(width, height); + } + + public static JBDimension size(int widthAndHeight) { + return new JBDimension(widthAndHeight, widthAndHeight); + } + + public static JBDimension size(Dimension size) { + if (size instanceof JBDimension) { + final JBDimension jbSize = (JBDimension)size; + if (jbSize.originalScale == scale(1f)) { + return jbSize; + } + final JBDimension newSize = new JBDimension((int)(jbSize.width / jbSize.originalScale), (int)(jbSize.height / jbSize.originalScale)); + return size instanceof UIResource ? newSize.asUIResource() : newSize; + } + return new JBDimension(size.width, size.height); + } + + public static JBInsets insets(int top, int left, int bottom, int right) { + return new JBInsets(top, left, bottom, right); + } + + public static JBInsets insets(int all) { + return insets(all, all, all, all); + } + + public static JBInsets insets(int topBottom, int leftRight) { + return insets(topBottom, leftRight, topBottom, leftRight); + } + + public static JBInsets emptyInsets() { + return new JBInsets(0, 0, 0, 0); + } + + public static JBInsets insetsTop(int t) { + return insets(t, 0, 0, 0); + } + + public static JBInsets insetsLeft(int l) { + return insets(0, l, 0, 0); + } + + public static JBInsets insetsBottom(int b) { + return insets(0, 0, b, 0); + } + + public static JBInsets insetsRight(int r) { + return insets(0, 0, 0, r); + } + + public static EmptyIcon emptyIcon(int i) { + return (EmptyIcon)EmptyIcon.create(scale(i)); + } + + public static JBDimension emptySize() { + return new JBDimension(0, 0); + } + + public static float scale(float f) { + return f * scaleFactor; + } + + public static JBInsets insets(Insets insets) { + return JBInsets.create(insets); + } + + public static boolean isHiDPI() { + return scaleFactor > 1.0f; + } + + public static class Fonts { + public static JBFont label() { + return JBFont.create(UIManager.getFont("Label.font"), false); + } + + public static JBFont label(float size) { + return label().deriveFont(scale(size)); + } + + public static JBFont smallFont() { + return label().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.SMALL)); + } + + public static JBFont miniFont() { + return label().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.MINI)); + } + + public static JBFont create(String fontFamily, int size) { + return JBFont.create(new Font(fontFamily, Font.PLAIN, size)); + } + } + + public static class Borders { + public static JBEmptyBorder empty(int top, int left, int bottom, int right) { + return new JBEmptyBorder(top, left, bottom, right); + } + + public static JBEmptyBorder empty(int topAndBottom, int leftAndRight) { + return empty(topAndBottom, leftAndRight, topAndBottom, leftAndRight); + } + + public static JBEmptyBorder emptyTop(int offset) { + return empty(offset, 0, 0, 0); + } + + public static JBEmptyBorder emptyLeft(int offset) { + return empty(0, offset, 0, 0); + } + + public static JBEmptyBorder emptyBottom(int offset) { + return empty(0, 0, offset, 0); + } + + public static JBEmptyBorder emptyRight(int offset) { + return empty(0, 0, 0, offset); + } + + public static JBEmptyBorder empty() { + return empty(0, 0, 0, 0); + } + + public static Border empty(int offsets) { + return empty(offsets, offsets, offsets, offsets); + } + +// public static Border customLine(Color color, int top, int left, int bottom, int right) { +// return new CustomLineBorder(color, insets(top, left, bottom, right)); +// } +// +// public static Border customLine(Color color, int thickness) { +// return customLine(color, thickness, thickness, thickness, thickness); +// } +// +// public static Border customLine(Color color) { +// return customLine(color, 1); +// } +// +// public static Border merge(@Nullable Border source, @NotNull Border extra, boolean extraIsOutside) { +// if (source == null) return extra; +// return new CompoundBorder(extraIsOutside ? extra : source, extraIsOutside? source : extra); +// } + } + +// public static class Panels { +// public static BorderLayoutPanel simplePanel() { +// return new BorderLayoutPanel(); +// } +// +// public static BorderLayoutPanel simplePanel(Component comp) { +// return simplePanel().addToCenter(comp); +// } +// +// public static BorderLayoutPanel simplePanel(int hgap, int vgap) { +// return new BorderLayoutPanel(hgap, vgap); +// } +// } +}