mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
UI DSL: visual paddings on a container level — macOS IntelliJ and macOS Darcula
This commit is contained in:
Generated
+3
@@ -1,6 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="miglayout-swing" type="repository">
|
||||
<properties maven-id="com.miglayout:miglayout-swing:5.1" />
|
||||
<ANNOTATIONS>
|
||||
<root url="file://$PROJECT_DIR$/lib/annotations/migLayout" />
|
||||
</ANNOTATIONS>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/miglayout/miglayout-swing/5.1/miglayout-swing-5.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/miglayout/miglayout-core/5.1/miglayout-core-5.1.jar!/" />
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<root>
|
||||
<item name='net.miginfocom.layout.ConstraintParser net.miginfocom.layout.BoundSize parseBoundSize(java.lang.String, boolean, boolean)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -1300,16 +1300,20 @@ public abstract class DialogWrapper {
|
||||
JComponent centerSection = new JPanel(new BorderLayout());
|
||||
root.add(centerSection, BorderLayout.CENTER);
|
||||
|
||||
root.setBorder(createContentPaneBorder());
|
||||
|
||||
final JComponent n = createNorthPanel();
|
||||
if (n != null) {
|
||||
centerSection.add(n, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
final JComponent c = createCenterPanel();
|
||||
if (c != null) {
|
||||
centerSection.add(c, BorderLayout.CENTER);
|
||||
final JComponent centerPanel = createCenterPanel();
|
||||
if (centerPanel != null) {
|
||||
centerSection.add(centerPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
boolean isVisualPaddingCompensatedOnComponentLevel = JBUI.isCompensateVisualPaddingOnComponentLevel(centerPanel);
|
||||
if (isVisualPaddingCompensatedOnComponentLevel) {
|
||||
// see comment about visual paddings in the MigLayoutBuilder.build
|
||||
root.setBorder(createContentPaneBorder());
|
||||
}
|
||||
|
||||
final JPanel southSection = new JPanel(new BorderLayout());
|
||||
@@ -1318,6 +1322,9 @@ public abstract class DialogWrapper {
|
||||
southSection.add(myErrorText, BorderLayout.CENTER);
|
||||
final JComponent south = createSouthPanel();
|
||||
if (south != null) {
|
||||
if (!isVisualPaddingCompensatedOnComponentLevel) {
|
||||
south.setBorder(JBUI.Borders.empty(0, 12, 8, 12));
|
||||
}
|
||||
southSection.add(south, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public interface VisualPaddingsProvider {
|
||||
@Nullable
|
||||
Insets
|
||||
getVisualPaddings(@NotNull Component component);
|
||||
}
|
||||
+11
-16
@@ -1,25 +1,14 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.ide.ui.laf.VisualPaddingsProvider;
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.MacUIUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
@@ -35,7 +24,7 @@ import static com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI.HELP_BUTTON_DIA
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class DarculaButtonPainter implements Border, UIResource {
|
||||
public class DarculaButtonPainter implements Border, UIResource, VisualPaddingsProvider {
|
||||
private static final int myOffset = 4;
|
||||
|
||||
@Override
|
||||
@@ -121,4 +110,10 @@ public class DarculaButtonPainter implements Border, UIResource {
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Insets getVisualPaddings(@NotNull Component component) {
|
||||
return JBUI.insets(3);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-16
@@ -1,22 +1,11 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.ide.ui.laf.VisualPaddingsProvider;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
@@ -26,7 +15,7 @@ import java.awt.*;
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class DarculaCheckBoxBorder implements Border, UIResource {
|
||||
public class DarculaCheckBoxBorder implements Border, UIResource, VisualPaddingsProvider {
|
||||
@Override
|
||||
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {}
|
||||
|
||||
@@ -39,4 +28,27 @@ public class DarculaCheckBoxBorder implements Border, UIResource {
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Insets getVisualPaddings(@NotNull Component component) {
|
||||
if (component instanceof JRadioButton) {
|
||||
if (((JRadioButton)component).getUI().getClass() == DarculaRadioButtonUI.class) {
|
||||
// darcula
|
||||
return JBUI.insets(0, 2, 0, 0);
|
||||
}
|
||||
else {
|
||||
// mac light
|
||||
return JBUI.insets(3, 3, 2, 0);
|
||||
}
|
||||
}
|
||||
else if (component instanceof JCheckBox && ((JCheckBox)component).getUI().getClass() == DarculaCheckBoxUI.class) {
|
||||
// darcula
|
||||
return JBUI.insets(0, 2, 0, 0);
|
||||
}
|
||||
else {
|
||||
// mac light
|
||||
return JBUI.insets(3, 4, 2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-15
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
@@ -45,6 +31,12 @@ public class DarculaCheckBoxUI extends MetalCheckBoxUI {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize(JComponent c) {
|
||||
Dimension size = super.getMinimumSize(c);
|
||||
return JBUI.isCompensateVisualPaddingOnComponentLevel(c.getParent()) ? size : new Dimension(size.width, DarculaTextFieldUI.DARCULA_INPUT_HEIGHT);
|
||||
}
|
||||
|
||||
@Override public void installDefaults(AbstractButton b) {
|
||||
super.installDefaults(b);
|
||||
b.setIconTextGap(textIconGap());
|
||||
|
||||
+19
-5
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.ide.ui.laf.VisualPaddingsProvider;
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
import com.intellij.openapi.ui.ComboBoxWithWidePopup;
|
||||
import com.intellij.openapi.ui.ErrorBorderCapable;
|
||||
@@ -37,7 +38,7 @@ import static com.intellij.ide.ui.laf.darcula.DarculaUIUtil.*;
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
@SuppressWarnings("GtkPreferredJComboBoxRenderer")
|
||||
public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorBorderCapable {
|
||||
public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorBorderCapable, VisualPaddingsProvider {
|
||||
|
||||
public DarculaComboBoxUI() {}
|
||||
|
||||
@@ -153,7 +154,8 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorB
|
||||
@NotNull
|
||||
static Dimension getArrowButtonPreferredSize(@Nullable JComboBox comboBox) {
|
||||
Insets i = comboBox != null ? comboBox.getInsets() : getDefaultComboBoxInsets();
|
||||
return new Dimension(JBUI.scale(16) + i.left, JBUI.scale(22) + i.top + i.bottom);
|
||||
int height = comboBox != null && JBUI.isUseCorrectInputHeightOnMacOS(comboBox) ? DarculaTextFieldUI.DARCULA_INPUT_HEIGHT : 22;
|
||||
return new Dimension(JBUI.scale(16) + i.left, JBUI.scale(height) + i.top + i.bottom);
|
||||
}
|
||||
|
||||
static Shape getArrowShape(Component button) {
|
||||
@@ -181,6 +183,9 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorB
|
||||
|
||||
@Override
|
||||
protected Insets getInsets() {
|
||||
if (JBUI.isUseCorrectInputHeightOnMacOS(comboBox)) {
|
||||
return JBUI.insets(2, 8, 2, 4).asUIResource();
|
||||
}
|
||||
return getDefaultComboBoxInsets().asUIResource();
|
||||
}
|
||||
|
||||
@@ -194,7 +199,9 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorB
|
||||
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
Rectangle r = new Rectangle(c.getSize());
|
||||
JBInsets.removeFrom(r, JBUI.insets(1));
|
||||
if (!JBUI.isUseCorrectInputHeightOnMacOS(comboBox)) {
|
||||
JBInsets.removeFrom(r, JBUI.insets(1));
|
||||
}
|
||||
|
||||
try {
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
@@ -327,7 +334,9 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorB
|
||||
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
|
||||
|
||||
Rectangle r = new Rectangle(x, y, width, height);
|
||||
JBInsets.removeFrom(r, JBUI.insets(1));
|
||||
if (!JBUI.isUseCorrectInputHeightOnMacOS(c)) {
|
||||
JBInsets.removeFrom(r, JBUI.insets(1));
|
||||
}
|
||||
|
||||
g2.translate(r.x, r.y);
|
||||
|
||||
@@ -389,7 +398,7 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorB
|
||||
Dimension abSize = arrowButton.getPreferredSize();
|
||||
|
||||
int editorHeight = editor != null ? editor.getPreferredSize().height + i.top + i.bottom : 0;
|
||||
int height = Math.max(Math.max(editorHeight, Math.max(abSize.height, d.height)), JBUI.scale(22) + i.top + i.bottom);
|
||||
int height = Math.max(Math.max(editorHeight, Math.max(abSize.height, d.height)), JBUI.scale(JBUI.isUseCorrectInputHeightOnMacOS(comboBox) ? DarculaTextFieldUI.DARCULA_INPUT_HEIGHT : 22) + i.top + i.bottom);
|
||||
int width = Math.max(d.width, abSize.width + JBUI.scale(10));
|
||||
|
||||
return new Dimension(width, height);
|
||||
@@ -529,4 +538,9 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border, ErrorB
|
||||
super.show(invoker, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getVisualPaddings(@NotNull Component component) {
|
||||
return JBUI.insets((int)bw());
|
||||
}
|
||||
}
|
||||
+7
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
@@ -69,7 +55,12 @@ public class DarculaPasswordFieldUI extends BasicPasswordFieldUI {
|
||||
public Dimension getPreferredSize(JComponent c) {
|
||||
Dimension size = super.getPreferredSize(c);
|
||||
Insets i = getComponent().getInsets();
|
||||
return new Dimension(size.width, Math.max(size.height, JBUI.scale(20) + i.top + i.bottom));
|
||||
return new Dimension(size.width, Math.max(size.height, JBUI.scale(JBUI.isCompensateVisualPaddingOnComponentLevel(c.getParent()) ? 20 : DarculaTextFieldUI.DARCULA_INPUT_HEIGHT) + i.top + i.bottom));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize(JComponent c) {
|
||||
return getPreferredSize(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-15
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
@@ -39,6 +25,12 @@ public class DarculaRadioButtonUI extends MetalRadioButtonUI {
|
||||
return new DarculaRadioButtonUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize(JComponent c) {
|
||||
Dimension size = super.getMinimumSize(c);
|
||||
return JBUI.isCompensateVisualPaddingOnComponentLevel(c.getParent()) ? size : new Dimension(size.width, DarculaTextFieldUI.DARCULA_INPUT_HEIGHT);
|
||||
}
|
||||
|
||||
@Override public void installDefaults(AbstractButton b) {
|
||||
super.installDefaults(b);
|
||||
b.setIconTextGap(JBUI.scale(4));
|
||||
|
||||
+23
-21
@@ -1,26 +1,15 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.ide.ui.laf.VisualPaddingsProvider;
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
import com.intellij.openapi.ui.ErrorBorderCapable;
|
||||
import com.intellij.ui.ColorPanel;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.MacUIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
@@ -35,13 +24,13 @@ import java.awt.geom.RoundRectangle2D;
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class DarculaTextBorder implements Border, UIResource, ErrorBorderCapable {
|
||||
public class DarculaTextBorder implements Border, UIResource, ErrorBorderCapable, VisualPaddingsProvider {
|
||||
@Override
|
||||
public Insets getBorderInsets(Component c) {
|
||||
if (c instanceof JTextField && c.getParent() instanceof ColorPanel) {
|
||||
return JBUI.insets(3, 3, 2, 2).asUIResource();
|
||||
}
|
||||
Insets insets = JBUI.insets(5, 9).asUIResource();
|
||||
Insets insets = JBUI.insets(JBUI.isCompensateVisualPaddingOnComponentLevel(c.getParent()) ? 5 : (int)bw(), 9).asUIResource();
|
||||
TextFieldWithPopupHandlerUI.updateBorderInsets(c, insets);
|
||||
return insets;
|
||||
}
|
||||
@@ -67,20 +56,27 @@ public class DarculaTextBorder implements Border, UIResource, ErrorBorderCapable
|
||||
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
|
||||
MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE);
|
||||
|
||||
JBInsets.removeFrom(r, JBUI.insets(1));
|
||||
Container parent = c.getParent();
|
||||
// if panel layout will compensate visual paddings, paint as MacComboBoxBorder does - do not translate to avoid complicating code (and logical expectations)
|
||||
if (JBUI.isCompensateVisualPaddingOnComponentLevel(parent)) {
|
||||
JBInsets.removeFrom(r, JBUI.insets(1));
|
||||
}
|
||||
|
||||
g2.translate(r.x, r.y);
|
||||
|
||||
Path2D border = new Path2D.Float(Path2D.WIND_EVEN_ODD);
|
||||
float lw = lw(g2);
|
||||
float bw = bw();
|
||||
border.append(new Rectangle2D.Float(bw, bw, r.width - bw * 2, r.height - bw * 2), false);
|
||||
border.append(new Rectangle2D.Float(bw + lw, bw + lw, r.width - (bw + lw) * 2, r.height - (bw + lw) * 2), false);
|
||||
|
||||
// paint as MacComboBoxBorder does - use passed width instead of r.width
|
||||
border.append(new Rectangle2D.Float(bw, bw, width - bw * 2, height - bw * 2), false);
|
||||
border.append(new Rectangle2D.Float(bw + lw, bw + lw, width - (bw + lw) * 2, height - (bw + lw) * 2), false);
|
||||
|
||||
boolean editable = !(c instanceof JTextComponent) || ((JTextComponent)c).isEditable();
|
||||
g2.setColor(getOutlineColor(c.isEnabled() && editable));
|
||||
g2.fill(border);
|
||||
|
||||
if (c.getParent() instanceof JComboBox) return;
|
||||
if (parent instanceof JComboBox) return;
|
||||
paint(c, g2, r.width, r.height, 0);
|
||||
}
|
||||
finally {
|
||||
@@ -167,4 +163,10 @@ public class DarculaTextBorder implements Border, UIResource, ErrorBorderCapable
|
||||
protected Color getOutlineColor(boolean enabled) {
|
||||
return DarculaUIUtil.getOutlineColor(enabled);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Insets getVisualPaddings(@NotNull Component component) {
|
||||
return JBUI.insets((int)bw());
|
||||
}
|
||||
}
|
||||
|
||||
+14
-18
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
@@ -28,19 +14,29 @@ import java.awt.geom.RoundRectangle2D;
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class DarculaTextFieldUI extends TextFieldWithPopupHandlerUI {
|
||||
protected static final int MACOS_LIGHT_INPUT_HEIGHT = 21;
|
||||
protected static final int DARCULA_INPUT_HEIGHT = 24;
|
||||
|
||||
@SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"})
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
return new DarculaTextFieldUI();
|
||||
}
|
||||
|
||||
// real height without visual paddings
|
||||
protected int getMinimumHeightForTextField() {
|
||||
return DARCULA_INPUT_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMinimumHeight() {
|
||||
Insets i = getComponent().getInsets();
|
||||
JComponent c = getComponent();
|
||||
return DarculaEditorTextFieldBorder.isComboBoxEditor(c) ||
|
||||
UIUtil.getParentOfType(JSpinner.class, c) != null ?
|
||||
JBUI.scale(22) : JBUI.scale(20) + i.top + i.bottom;
|
||||
if (DarculaEditorTextFieldBorder.isComboBoxEditor(c) || UIUtil.getParentOfType(JSpinner.class, c) != null) {
|
||||
return JBUI.scale(JBUI.getInt("TextFieldUI.spinnerOrComboboxEditorHeight", 22));
|
||||
}
|
||||
else {
|
||||
return JBUI.scale(JBUI.isUseCorrectInputHeightOnMacOS(c) ? getMinimumHeightForTextField() : 22) + i.top + i.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.MacUIUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -165,4 +153,10 @@ public class MacComboBoxBorder extends MacIntelliJTextBorder {
|
||||
protected boolean isSymmetric() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Insets getVisualPaddings(@NotNull Component component) {
|
||||
return JBUI.insets(3, 3, 3, 4);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-16
@@ -1,23 +1,12 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ide.ui.laf.VisualPaddingsProvider;
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
@@ -29,7 +18,7 @@ import static com.intellij.ide.ui.laf.intellij.MacIntelliJButtonUI.ARC_SIZE;
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class MacIntelliJButtonBorder implements Border, UIResource {
|
||||
public class MacIntelliJButtonBorder implements Border, UIResource, VisualPaddingsProvider {
|
||||
@Override
|
||||
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
|
||||
if (!c.hasFocus() || c instanceof JComponent && UIUtil.isHelpButton(c)) return;
|
||||
@@ -52,4 +41,10 @@ public class MacIntelliJButtonBorder implements Border, UIResource {
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Insets getVisualPaddings(@NotNull Component component) {
|
||||
return JBUI.insets(3);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.ui.DarculaComboBoxUI;
|
||||
@@ -154,8 +140,9 @@ public class MacIntelliJComboBoxUI extends DarculaComboBoxUI {
|
||||
int iconWidth = DEFAULT_ICON.getIconWidth() + i.right;
|
||||
int iconHeight = DEFAULT_ICON.getIconHeight() + i.top + i.bottom;
|
||||
int editorHeight = editor != null ? editor.getPreferredSize().height + i.top + i.bottom : 0;
|
||||
int maxHeight = JBUI.scale(JBUI.isUseCorrectInputHeightOnMacOS(comboBox) ? MacIntelliJTextFieldUI.MACOS_LIGHT_INPUT_HEIGHT_TOTAL : 26);
|
||||
return new Dimension(Math.max(d.width + JBUI.scale(7), iconWidth),
|
||||
Math.max(Math.max(iconHeight, editorHeight), JBUI.scale(26)));
|
||||
Math.max(Math.max(iconHeight, editorHeight), maxHeight));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+20
-17
@@ -1,21 +1,8 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.ui.DarculaPasswordFieldUI;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -45,7 +32,12 @@ public class MacIntelliJPasswordFieldUI extends DarculaPasswordFieldUI {
|
||||
|
||||
if (c.getBorder() instanceof MacIntelliJTextBorder) {
|
||||
g.setColor(c.getBackground());
|
||||
g.fillRect(3, 3, c.getWidth() - 6, c.getHeight() - 6);
|
||||
if (JBUI.isCompensateVisualPaddingOnComponentLevel(parent)) {
|
||||
g.fillRect(3, 3, c.getWidth() - 6, c.getHeight() - 6);
|
||||
}
|
||||
else {
|
||||
g.fillRect(5, 5, c.getWidth() - 6 - MacIntelliJTextFieldUI.BW, c.getHeight() - 6 - MacIntelliJTextFieldUI.BW);
|
||||
}
|
||||
} else {
|
||||
super.paintBackground(g);
|
||||
}
|
||||
@@ -55,6 +47,17 @@ public class MacIntelliJPasswordFieldUI extends DarculaPasswordFieldUI {
|
||||
@Override
|
||||
public Dimension getPreferredSize(JComponent c) {
|
||||
Dimension size = super.getPreferredSize(c);
|
||||
return new Dimension(size.width, Math.max(26, size.height));
|
||||
if (JBUI.isCompensateVisualPaddingOnComponentLevel(c.getParent())) {
|
||||
return new Dimension(size.width, Math.max(26, size.height));
|
||||
}
|
||||
else {
|
||||
return new Dimension(size.width, MacIntelliJTextFieldUI.MACOS_LIGHT_INPUT_HEIGHT_TOTAL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize(JComponent c) {
|
||||
Dimension size = super.getMinimumSize(c);
|
||||
return JBUI.isCompensateVisualPaddingOnComponentLevel(c.getParent()) ? size : new Dimension(size.width, MacIntelliJTextFieldUI.MACOS_LIGHT_INPUT_HEIGHT_TOTAL);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
@@ -100,7 +86,9 @@ public class MacIntelliJTextBorder extends DarculaTextBorder {
|
||||
if (c instanceof JTextField && c.getParent() instanceof ColorPanel) {
|
||||
return JBUI.insets(3, 3, 2, 2).asUIResource();
|
||||
}
|
||||
Insets insets = JBUI.insets(5, 8).asUIResource();
|
||||
|
||||
int topBottom = JBUI.isCompensateVisualPaddingOnComponentLevel(c.getParent()) ? 5 : 3;
|
||||
Insets insets = JBUI.insets(topBottom, 8).asUIResource();
|
||||
TextFieldWithPopupHandlerUI.updateBorderInsets(c, insets);
|
||||
return insets;
|
||||
}
|
||||
|
||||
+14
-17
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.ui.DarculaEditorTextFieldBorder;
|
||||
@@ -29,6 +15,8 @@ import java.awt.*;
|
||||
* @author Sergey Malenkov
|
||||
*/
|
||||
public class MacIntelliJTextFieldUI extends DarculaTextFieldUI {
|
||||
public static final int BW = 3;
|
||||
public static final int MACOS_LIGHT_INPUT_HEIGHT_TOTAL = MACOS_LIGHT_INPUT_HEIGHT + (BW * 2);
|
||||
|
||||
@SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"})
|
||||
public static ComponentUI createUI(final JComponent c) {
|
||||
@@ -47,13 +35,22 @@ public class MacIntelliJTextFieldUI extends DarculaTextFieldUI {
|
||||
search.bounds.x = bounds.x + (bounds.width - search.bounds.width) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMinimumHeightForTextField() {
|
||||
return DarculaTextFieldUI.MACOS_LIGHT_INPUT_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMinimumHeight() {
|
||||
return DarculaEditorTextFieldBorder.isComboBoxEditor(getComponent()) ? JBUI.scale(18) : JBUI.scale(26);
|
||||
JTextComponent component = getComponent();
|
||||
if (JBUI.isUseCorrectInputHeightOnMacOS(component)) {
|
||||
return super.getMinimumHeight();
|
||||
}
|
||||
return DarculaEditorTextFieldBorder.isComboBoxEditor(component) ? JBUI.scale(18) : JBUI.scale(26);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float bw() {
|
||||
return JBUI.scale(3);
|
||||
return JBUI.scale(BW);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ TextField.disabledBackground=ececec
|
||||
PasswordFieldUI=com.intellij.ide.ui.laf.intellij.MacIntelliJPasswordFieldUI
|
||||
PasswordField.border=com.intellij.ide.ui.laf.intellij.MacIntelliJTextBorder
|
||||
|
||||
TextFieldUI.spinnerOrComboboxEditorHeight=21
|
||||
|
||||
SpinnerUI=com.intellij.ide.ui.laf.intellij.MacIntelliJSpinnerUI
|
||||
Spinner.border=com.intellij.ide.ui.laf.intellij.MacIntelliJSpinnerBorder
|
||||
|
||||
|
||||
@@ -124,6 +124,9 @@ private fun setTitledBorder(title: String, panel: JPanel) {
|
||||
border.acceptMinimumSize(panel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider using [UI DSL](https://github.com/JetBrains/intellij-community/tree/master/platform/platform-impl/src/com/intellij/ui/layout#readme) to create panel.
|
||||
*/
|
||||
fun dialog(title: String,
|
||||
panel: JComponent,
|
||||
resizable: Boolean = false,
|
||||
|
||||
@@ -26,7 +26,11 @@ import javax.swing.JButton
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JLabel
|
||||
|
||||
@DslMarker
|
||||
annotation class CellMarker
|
||||
|
||||
// separate class to avoid row related methods in the `cell { } `
|
||||
@CellMarker
|
||||
abstract class Cell {
|
||||
/**
|
||||
* Sets how keen the component should be to grow in relation to other component **in the same cell**. Use `push` in addition if need.
|
||||
@@ -56,10 +60,10 @@ abstract class Cell {
|
||||
result()
|
||||
}
|
||||
|
||||
fun button(text: String, actionListener: (event: ActionEvent) -> Unit) {
|
||||
fun button(text: String, vararg constraints: CCFlags, actionListener: (event: ActionEvent) -> Unit) {
|
||||
val button = JButton(BundleBase.replaceMnemonicAmpersand(text))
|
||||
button.addActionListener(actionListener)
|
||||
button()
|
||||
button(*constraints)
|
||||
}
|
||||
|
||||
fun textFieldWithBrowseButton(browseDialogTitle: String,
|
||||
|
||||
@@ -62,14 +62,6 @@ abstract class Row : Cell() {
|
||||
@PublishedApi
|
||||
internal abstract fun setCellMode(value: Boolean)
|
||||
|
||||
@Deprecated(message = "Nested row is prohibited", level = DeprecationLevel.ERROR)
|
||||
fun row(label: JLabel? = null, init: Row.() -> Unit) {
|
||||
}
|
||||
|
||||
@Deprecated(message = "Nested noteRow is prohibited", level = DeprecationLevel.ERROR)
|
||||
fun noteRow(text: String) {
|
||||
}
|
||||
|
||||
// override here for backward compatibility
|
||||
@Deprecated(level = DeprecationLevel.HIDDEN, message = "deprecated")
|
||||
operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int = 0, growPolicy: GrowPolicy? = null) {
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.layout
|
||||
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.ui.components.Panel
|
||||
import com.intellij.util.ui.JBUI
|
||||
import javax.swing.JPanel
|
||||
|
||||
/**
|
||||
* See [docs](https://github.com/JetBrains/intellij-community/tree/master/platform/platform-impl/src/com/intellij/ui/layout).
|
||||
*
|
||||
* Claims all available space in the container for the columns ([LCFlags.fillX], if `constraints` is passed, `fillX` will be not applied - add it explicitly if need).
|
||||
* At least one component need to have a [Row.grow] constraint for it to fill the container.
|
||||
*
|
||||
* See [docs](https://github.com/JetBrains/intellij-community/tree/master/platform/platform-impl/src/com/intellij/ui/layout).
|
||||
*
|
||||
* Check `Tools -> Internal Actions -> UI -> UI DSL Debug Mode` to turn on debug painting.
|
||||
*
|
||||
* `JTextComponent`, `TextFieldWithHistory` (use [Row.textFieldWithBrowseButton]), `SeparatorComponent` and `ComponentWithBrowseButton` components automatically have [Row.growX].
|
||||
@@ -21,6 +23,9 @@ inline fun panel(vararg constraints: LCFlags, title: String? = null, init: Layou
|
||||
builder.init()
|
||||
|
||||
val panel = Panel(title, layout = null)
|
||||
if (SystemInfoRt.isMac) {
|
||||
panel.putClientProperty(JBUI.COMPENSATE_VISUAL_PADDING_KEY, false)
|
||||
}
|
||||
builder.builder.build(panel, constraints)
|
||||
return panel
|
||||
}
|
||||
@@ -1,19 +1,46 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.layout
|
||||
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.ui.layout.migLayout.*
|
||||
import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import java.awt.Container
|
||||
import javax.swing.ButtonGroup
|
||||
import javax.swing.JLabel
|
||||
|
||||
// see com.intellij.uiDesigner.core.AbstractLayout.DEFAULT_HGAP and DEFAULT_VGAP
|
||||
// https://docs.google.com/document/d/1DKnLkO-7_onA7_NCw669aeMH5ltNvw-QMiQHnXu8k_Y/edit
|
||||
|
||||
// https://jetbrains.github.io/ui/controls/input_field/#spacing
|
||||
@PublishedApi
|
||||
internal fun createLayoutBuilder() = LayoutBuilder(MigLayoutBuilder(horizontalGap = UIUtil.DEFAULT_HGAP,
|
||||
verticalGap = UIUtil.DEFAULT_VGAP,
|
||||
largeVerticalGap = UIUtil.LARGE_VGAP))
|
||||
internal fun createLayoutBuilder(): LayoutBuilder {
|
||||
// https://jetbrains.github.io/ui/controls/input_field/#spacing
|
||||
val isUnderIntelliJLaF = UIUtil.isUnderIntelliJLaF()
|
||||
|
||||
|
||||
val labelColumnVerticalTopGap = when {
|
||||
SystemInfoRt.isMac && isUnderIntelliJLaF -> 2
|
||||
else -> 4
|
||||
}
|
||||
|
||||
val spacing = object : SpacingConfiguration {
|
||||
override val labelColumnVerticalTopGap = JBUI.scale(labelColumnVerticalTopGap)
|
||||
|
||||
override val isCompensateVisualPaddings = SystemInfoRt.isMac
|
||||
|
||||
override val horizontalGap = JBUI.scale(8)
|
||||
override val verticalGap = JBUI.scale(5 * 2)
|
||||
override val labelColumnHorizontalGap = JBUI.scale(6)
|
||||
override val largeVerticalGap = JBUI.scale(UIUtil.LARGE_VGAP)
|
||||
|
||||
override val shortTextWidth = JBUI.scale(250)
|
||||
override val maxShortTextWidth = JBUI.scale(350)
|
||||
|
||||
override val unitSize = JBUI.scale(4)
|
||||
|
||||
override val dialogTopBottom = JBUI.scale(8)
|
||||
override val dialogLeftRight = JBUI.scale(12)
|
||||
}
|
||||
return LayoutBuilder(MigLayoutBuilder(spacing))
|
||||
}
|
||||
|
||||
interface LayoutBuilderImpl {
|
||||
fun newRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false): Row
|
||||
@@ -21,4 +48,51 @@ interface LayoutBuilderImpl {
|
||||
fun build(container: Container, layoutConstraints: Array<out LCFlags>)
|
||||
|
||||
fun noteRow(text: String, linkHandler: ((url: String) -> Unit)? = null)
|
||||
}
|
||||
|
||||
internal interface SpacingConfiguration {
|
||||
/**
|
||||
* Horizontal space between two components (in terms of layout grid - cells).
|
||||
*
|
||||
* It is space between associated components (somehow relates to each other) - for example, combobox and button to delete items from combobox.
|
||||
* Since in most cases components in cells will be associated, it is not a space between two independent components.
|
||||
* Horizontal subgroups of components is not supported yet, that's why there is no property to define such space.
|
||||
*/
|
||||
val horizontalGap: Int
|
||||
|
||||
/**
|
||||
* Vertical space between two components (in terms of layout grid - rows).
|
||||
*/
|
||||
val verticalGap: Int
|
||||
|
||||
/**
|
||||
* Horizontal gap after label column.
|
||||
*/
|
||||
val labelColumnHorizontalGap: Int
|
||||
|
||||
val labelColumnVerticalTopGap: Int
|
||||
|
||||
val largeVerticalGap: Int
|
||||
|
||||
/**
|
||||
* On macOS input fields (text fields, checkboxes, buttons and so on) have focus ring that drawn outside of component border.
|
||||
* If reported component dimensions will be equals to visible (when unfocused) component dimensions, focus ring will be clipped.
|
||||
*
|
||||
* Since LaF cannot control component environment (host component), default safe strategy is to report component dimensions including focus ring.
|
||||
* But it leads to an issue - spacing specified for visible component borders, not to compensated. For example, if horizontal space must be 8px,
|
||||
* this 8px must be between one visible border of component to another visible border (in the case of macOS Light theme, gray 1px borders).
|
||||
* Exactly 8px.
|
||||
*
|
||||
* So, advanced layout engine, e.g. MigLayout, offers a way to compensate visual padding on the layout container level, not on component level, as a solution.
|
||||
*/
|
||||
val isCompensateVisualPaddings: Boolean
|
||||
|
||||
val shortTextWidth: Int
|
||||
val maxShortTextWidth: Int
|
||||
|
||||
// row comment top gap or gear icon left gap
|
||||
val unitSize: Int
|
||||
|
||||
val dialogTopBottom: Int
|
||||
val dialogLeftRight: Int
|
||||
}
|
||||
@@ -9,19 +9,18 @@ import net.miginfocom.swing.MigLayout
|
||||
import java.awt.Component
|
||||
import java.awt.Container
|
||||
import javax.swing.ButtonGroup
|
||||
import javax.swing.JDialog
|
||||
import javax.swing.JLabel
|
||||
|
||||
/**
|
||||
* Automatically add `growX` to JTextComponent (see isAddGrowX).
|
||||
* Automatically add `grow` and `push` to JPanel (see isAddGrowX).
|
||||
*/
|
||||
internal class MigLayoutBuilder(val horizontalGap: Int, val verticalGap: Int, val largeVerticalGap: Int) : LayoutBuilderImpl {
|
||||
internal class MigLayoutBuilder(val spacing: SpacingConfiguration) : LayoutBuilderImpl {
|
||||
/**
|
||||
* Map of component to constraints shared among rows (since components are unique)
|
||||
*/
|
||||
private val componentConstraints: MutableMap<Component, CC> = ContainerUtil.newIdentityTroveMap()
|
||||
private val rootRow = MigLayoutRow(parent = null, componentConstraints = componentConstraints, builder = this, indent = 0)
|
||||
|
||||
val defaultComponentConstraintCreator = DefaultComponentConstraintCreator(spacing)
|
||||
|
||||
val columnConstraints = AC()
|
||||
|
||||
override fun newRow(label: JLabel?, buttonGroup: ButtonGroup?, separated: Boolean): Row {
|
||||
@@ -30,8 +29,8 @@ internal class MigLayoutBuilder(val horizontalGap: Int, val verticalGap: Int, va
|
||||
|
||||
override fun noteRow(text: String, linkHandler: ((url: String) -> Unit)?) {
|
||||
val cc = CC()
|
||||
cc.vertical.gapBefore = gapToBoundSize(if (rootRow.subRows == null) verticalGap else largeVerticalGap, false)
|
||||
cc.vertical.gapAfter = gapToBoundSize(horizontalGap, false)
|
||||
cc.vertical.gapBefore = gapToBoundSize(if (rootRow.subRows == null) spacing.verticalGap else spacing.largeVerticalGap, false)
|
||||
cc.vertical.gapAfter = gapToBoundSize(spacing.verticalGap * 2, false)
|
||||
|
||||
val row = rootRow.createChildRow(label = null, noGrid = true)
|
||||
row.apply {
|
||||
@@ -42,7 +41,10 @@ internal class MigLayoutBuilder(val horizontalGap: Int, val verticalGap: Int, va
|
||||
}
|
||||
|
||||
override fun build(container: Container, layoutConstraints: Array<out LCFlags>) {
|
||||
val lc = createLayoutConstraints(horizontalGap, verticalGap)
|
||||
val lc = LC()
|
||||
lc.gridGapX = gapToBoundSize(0, true)
|
||||
lc.gridGapY = gapToBoundSize(spacing.verticalGap, false)
|
||||
lc.insets("0px")
|
||||
if (layoutConstraints.isEmpty()) {
|
||||
lc.fillX()
|
||||
// not fillY because it leads to enormously large cells - we use cc `push` in addition to cc `grow` as a more robust and easy solution
|
||||
@@ -51,18 +53,49 @@ internal class MigLayoutBuilder(val horizontalGap: Int, val verticalGap: Int, va
|
||||
lc.apply(layoutConstraints)
|
||||
}
|
||||
|
||||
lc.noVisualPadding()
|
||||
lc.isVisualPadding = spacing.isCompensateVisualPaddings
|
||||
lc.hideMode = 3
|
||||
|
||||
if (rootRow.subRows!!.any { it.isLabeledIncludingSubRows }) {
|
||||
// using columnConstraints instead of component gap allows easy debug (proper painting of debug grid)
|
||||
columnConstraints.gap("${spacing.labelColumnHorizontalGap}px!", 0)
|
||||
}
|
||||
|
||||
for (i in 1 until columnConstraints.count) {
|
||||
columnConstraints.gap("${spacing.horizontalGap}px!", i)
|
||||
}
|
||||
|
||||
// if constraint specified only for rows 0 and 1, MigLayout will use constraint 1 for any rows with index 1+ (see LayoutUtil.getIndexSafe - use last element if index > size)
|
||||
val rowConstraints = AC()
|
||||
rowConstraints.align("top")
|
||||
container.layout = MigLayout(lc, columnConstraints, rowConstraints)
|
||||
|
||||
var isLayoutInsetsAdjusted = false
|
||||
container.layout = object : MigLayout(lc, columnConstraints, rowConstraints) {
|
||||
override fun layoutContainer(parent: Container) {
|
||||
if (!isLayoutInsetsAdjusted) {
|
||||
isLayoutInsetsAdjusted = true
|
||||
|
||||
var topParent = parent.parent
|
||||
while (topParent != null) {
|
||||
if (topParent is JDialog) {
|
||||
val topBottom = createUnitValue(spacing.dialogTopBottom, false)
|
||||
val leftRight = createUnitValue(spacing.dialogLeftRight, true)
|
||||
// since we compensate visual padding, child components should be not clipped, so, we do not use content pane DialogWrapper border (returns null),
|
||||
// but instead set insets to our content panel (so, child components are not clipped)
|
||||
lc.insets = arrayOf(topBottom, leftRight, topBottom, leftRight)
|
||||
break
|
||||
}
|
||||
topParent = topParent.parent
|
||||
}
|
||||
}
|
||||
|
||||
super.layoutContainer(parent)
|
||||
}
|
||||
}
|
||||
|
||||
val isNoGrid = layoutConstraints.contains(LCFlags.noGrid)
|
||||
|
||||
var rowIndex = 0
|
||||
|
||||
fun configureComponents(row: MigLayoutRow) {
|
||||
val lastComponent = row.components.lastOrNull()
|
||||
for ((index, component) in row.components.withIndex()) {
|
||||
@@ -74,6 +107,8 @@ internal class MigLayoutBuilder(val horizontalGap: Int, val verticalGap: Int, va
|
||||
continue
|
||||
}
|
||||
|
||||
// we cannot use columnCount as an indicator of whether to use spanX/wrap or not because component can share cell with another component,
|
||||
// in any case MigLayout is smart enough and unnecessary spanX/wrap doesn't harm
|
||||
if (component === lastComponent) {
|
||||
cc.spanX()
|
||||
cc.wrap()
|
||||
@@ -119,18 +154,12 @@ internal class MigLayoutBuilder(val horizontalGap: Int, val verticalGap: Int, va
|
||||
}
|
||||
|
||||
internal fun gapToBoundSize(value: Int, isHorizontal: Boolean): BoundSize {
|
||||
val unitValue = UnitValue(value.toFloat(), "px", isHorizontal, UnitValue.STATIC, null)
|
||||
val unitValue = createUnitValue(value, isHorizontal)
|
||||
return BoundSize(unitValue, unitValue, null, false, null)
|
||||
}
|
||||
|
||||
// default values differs to MigLayout - IntelliJ Platform defaults are used
|
||||
private fun createLayoutConstraints(gridGapX: Int, gridGapY: Int): LC {
|
||||
val lc = LC()
|
||||
// gap multiplied by 2 (it seems in terms of MigLayout gap is both left and right space)
|
||||
lc.gridGapX = gapToBoundSize(gridGapX * 2, true)
|
||||
lc.gridGapY = gapToBoundSize(gridGapY, false)
|
||||
lc.insets = ConstraintParser.parseInsets("0px", true)
|
||||
return lc
|
||||
private fun createUnitValue(value: Int, isHorizontal: Boolean): UnitValue {
|
||||
return UnitValue(value.toFloat(), "px", isHorizontal, UnitValue.STATIC, null)
|
||||
}
|
||||
|
||||
private fun LC.apply(flags: Array<out LCFlags>): LC {
|
||||
|
||||
@@ -3,19 +3,19 @@ package com.intellij.ui.layout.migLayout
|
||||
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ide.ui.laf.VisualPaddingsProvider
|
||||
import com.intellij.openapi.ui.OnePixelDivider
|
||||
import com.intellij.openapi.ui.panel.ComponentPanelBuilder
|
||||
import com.intellij.ui.SeparatorComponent
|
||||
import com.intellij.ui.components.Label
|
||||
import com.intellij.ui.layout.*
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import net.miginfocom.layout.CC
|
||||
import net.miginfocom.layout.ConstraintParser
|
||||
import net.miginfocom.layout.PlatformDefaults
|
||||
import java.awt.Component
|
||||
import javax.swing.*
|
||||
|
||||
private val LABEL_TOP_GAP = ConstraintParser.parseBoundSize("4px!", true, false)
|
||||
import javax.swing.border.LineBorder
|
||||
|
||||
internal class MigLayoutRow(private val parent: MigLayoutRow?,
|
||||
private val componentConstraints: MutableMap<Component, CC>,
|
||||
@@ -39,70 +39,8 @@ internal class MigLayoutRow(private val parent: MigLayoutRow?,
|
||||
|
||||
private var componentIndexWhenCellModeWasEnabled = -1
|
||||
|
||||
fun createChildRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false, noGrid: Boolean = false): MigLayoutRow {
|
||||
if (subRows == null) {
|
||||
subRows = SmartList()
|
||||
}
|
||||
|
||||
val subRows = subRows!!
|
||||
|
||||
if (separated) {
|
||||
val row = MigLayoutRow(this, componentConstraints, builder, indent = indent, noGrid = true)
|
||||
subRows.add(row)
|
||||
row.apply {
|
||||
val separatorComponent = SeparatorComponent(0, OnePixelDivider.BACKGROUND, null)
|
||||
val cc = CC()
|
||||
cc.vertical.gapBefore = gapToBoundSize(builder.largeVerticalGap, false)
|
||||
cc.vertical.gapAfter = gapToBoundSize(builder.verticalGap * 2, false)
|
||||
componentConstraints.put(separatorComponent, cc)
|
||||
separatorComponent()
|
||||
}
|
||||
}
|
||||
|
||||
val row = MigLayoutRow(this, componentConstraints, builder, labeled = label != null, noGrid = noGrid, indent = indent + computeChildRowIndent(), buttonGroup = buttonGroup)
|
||||
subRows.add(row)
|
||||
|
||||
if (label != null) {
|
||||
val labelComponentConstraints = CC()
|
||||
labelComponentConstraints.vertical.gapBefore = LABEL_TOP_GAP
|
||||
componentConstraints.put(label, labelComponentConstraints)
|
||||
row.addComponent(label)
|
||||
}
|
||||
|
||||
return row
|
||||
}
|
||||
|
||||
// cell mode not tested with "gear" button, wait first user request
|
||||
override fun setCellMode(value: Boolean) {
|
||||
if (value) {
|
||||
assert(componentIndexWhenCellModeWasEnabled == -1)
|
||||
componentIndexWhenCellModeWasEnabled = components.size
|
||||
}
|
||||
else {
|
||||
val firstComponentIndex = componentIndexWhenCellModeWasEnabled
|
||||
componentIndexWhenCellModeWasEnabled = -1
|
||||
// do not add split if cell empty or contains the only component
|
||||
if ((components.size - firstComponentIndex) > 1) {
|
||||
val component = components.get(firstComponentIndex)
|
||||
componentConstraints.getOrPut(component) { CC() }.split(components.size - firstComponentIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeChildRowIndent(): Int {
|
||||
if (components.isEmpty()) {
|
||||
return 0
|
||||
}
|
||||
else {
|
||||
val firstComponent = components.first()
|
||||
if (firstComponent is JRadioButton || firstComponent is JCheckBox) {
|
||||
return ComponentPanelBuilder.computeCommentInsets(firstComponent, true).left
|
||||
}
|
||||
else {
|
||||
return builder.horizontalGap * 3
|
||||
}
|
||||
}
|
||||
}
|
||||
private val spacing: SpacingConfiguration
|
||||
get() = builder.spacing
|
||||
|
||||
override var enabled: Boolean = true
|
||||
set(value) {
|
||||
@@ -148,29 +86,117 @@ internal class MigLayoutRow(private val parent: MigLayoutRow?,
|
||||
subRows?.forEach { it.visible = value }
|
||||
}
|
||||
|
||||
internal val isLabeledIncludingSubRows: Boolean
|
||||
get() = labeled || (subRows?.any { it.isLabeledIncludingSubRows } ?: false)
|
||||
|
||||
fun createChildRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false, noGrid: Boolean = false): MigLayoutRow {
|
||||
if (subRows == null) {
|
||||
subRows = SmartList()
|
||||
}
|
||||
|
||||
val subRows = subRows!!
|
||||
|
||||
if (separated) {
|
||||
val row = MigLayoutRow(this, componentConstraints, builder, indent = indent, noGrid = true)
|
||||
subRows.add(row)
|
||||
row.apply {
|
||||
val separatorComponent = SeparatorComponent(0, OnePixelDivider.BACKGROUND, null)
|
||||
val cc = CC()
|
||||
cc.vertical.gapBefore = gapToBoundSize(spacing.largeVerticalGap, false)
|
||||
cc.vertical.gapAfter = gapToBoundSize(spacing.verticalGap * 2, false)
|
||||
componentConstraints.put(separatorComponent, cc)
|
||||
addComponent(separatorComponent, lazyOf(cc))
|
||||
}
|
||||
}
|
||||
|
||||
val row = MigLayoutRow(this, componentConstraints, builder, labeled = label != null, noGrid = noGrid,
|
||||
indent = indent + computeChildRowIndent(), buttonGroup = buttonGroup)
|
||||
subRows.add(row)
|
||||
|
||||
if (label != null) {
|
||||
val labelComponentConstraints = CC()
|
||||
labelComponentConstraints.vertical.gapBefore = ConstraintParser.parseBoundSize("${spacing.labelColumnVerticalTopGap}px!", true, false)
|
||||
componentConstraints.put(label, labelComponentConstraints)
|
||||
row.addComponent(label, lazyOf(labelComponentConstraints))
|
||||
}
|
||||
|
||||
return row
|
||||
}
|
||||
|
||||
// cell mode not tested with "gear" button, wait first user request
|
||||
override fun setCellMode(value: Boolean) {
|
||||
if (value) {
|
||||
assert(componentIndexWhenCellModeWasEnabled == -1)
|
||||
componentIndexWhenCellModeWasEnabled = components.size
|
||||
}
|
||||
else {
|
||||
val firstComponentIndex = componentIndexWhenCellModeWasEnabled
|
||||
componentIndexWhenCellModeWasEnabled = -1
|
||||
// do not add split if cell empty or contains the only component
|
||||
if ((components.size - firstComponentIndex) > 1) {
|
||||
val component = components.get(firstComponentIndex)
|
||||
componentConstraints.getOrPut(component) { CC() }.split(components.size - firstComponentIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeChildRowIndent(): Int {
|
||||
val firstComponent = components.firstOrNull() ?: return 0
|
||||
if (firstComponent is JRadioButton || firstComponent is JCheckBox) {
|
||||
return getCommentLeftInset(firstComponent)
|
||||
}
|
||||
else {
|
||||
return spacing.horizontalGap * 3
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCommentLeftInset(component: JComponent): Int {
|
||||
if (component is JTextField) {
|
||||
// 1px border, better to indent comment text
|
||||
return 1
|
||||
}
|
||||
|
||||
// as soon as ComponentPanelBuilder will also compensate visual paddings (instead of compensating on LaF level),
|
||||
// this logic will be moved into computeCommentInsets
|
||||
val componentBorderVisualLeftPadding = (component.border as? VisualPaddingsProvider)?.getVisualPaddings(component)?.left ?: 0
|
||||
val insets = ComponentPanelBuilder.computeCommentInsets(component, true)
|
||||
return insets.left - componentBorderVisualLeftPadding
|
||||
}
|
||||
|
||||
override operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int, growPolicy: GrowPolicy?, comment: String?) {
|
||||
addComponent(this, constraints, gapLeft, growPolicy, comment)
|
||||
addComponent(this, constraints.create()?.let { lazyOf(it) } ?: lazy { CC() }, gapLeft, growPolicy, comment)
|
||||
}
|
||||
|
||||
// separate method to avoid JComponent as a receiver
|
||||
private fun addComponent(component: JComponent,
|
||||
constraints: Array<out CCFlags>? = null,
|
||||
gapLeft: Int = 0,
|
||||
growPolicy: GrowPolicy? = null,
|
||||
comment: String? = null) {
|
||||
private fun addComponent(component: JComponent, cc: Lazy<CC>, gapLeft: Int = 0, growPolicy: GrowPolicy? = null, comment: String? = null) {
|
||||
components.add(component)
|
||||
|
||||
if (!shareCellWithPreviousComponentIfNeed(component, cc)) {
|
||||
// increase column index if cell mode not enabled or it is a first component of cell
|
||||
if (componentIndexWhenCellModeWasEnabled == -1 || componentIndexWhenCellModeWasEnabled == (components.size - 1)) {
|
||||
columnIndex++
|
||||
}
|
||||
}
|
||||
|
||||
setVisualPaddingsAndLabelTopGapIfNeed(component)
|
||||
|
||||
// (not yet clear is it true or just some strange gaps from another source) MigLayout compensate outer visual paddings, but if there are more than one component in the cell,
|
||||
// inner horizontal spacing will be not corrected (e.g. between combobox and button will be 7px horizontal gap in case of macOS IntelliJ LaF), as solution, we set horizontal gap for such components).
|
||||
// if it is not a first component in the cell, compensate horizontal visual paddings using gap.
|
||||
if (componentIndexWhenCellModeWasEnabled != -1 && componentIndexWhenCellModeWasEnabled < (components.size - 1)) {
|
||||
cc.value.horizontal.gapBefore = gapToBoundSize(spacing.horizontalGap, true)
|
||||
}
|
||||
|
||||
if (comment != null && comment.isNotEmpty()) {
|
||||
gapAfter = "0px!"
|
||||
gapAfter = "${spacing.unitSize}px!"
|
||||
|
||||
val isParentRowLabeled = labeled
|
||||
// create comment in a new sibling row (developer is still able to create sub rows because rows is not stored in a flat list)
|
||||
parent!!.createChildRow().apply {
|
||||
val commentComponent = ComponentPanelBuilder.createCommentComponent(comment, true)
|
||||
addComponent(commentComponent)
|
||||
|
||||
val commentComponentCC = CC()
|
||||
commentComponentCC.horizontal.gapBefore = gapToBoundSize(ComponentPanelBuilder.computeCommentInsets(component, true).left, true)
|
||||
addComponent(commentComponent, lazyOf(commentComponentCC))
|
||||
commentComponentCC.horizontal.gapBefore = gapToBoundSize(getCommentLeftInset(component), true)
|
||||
if (isParentRowLabeled) {
|
||||
commentComponentCC.skip()
|
||||
}
|
||||
@@ -182,28 +208,12 @@ internal class MigLayoutRow(private val parent: MigLayoutRow?,
|
||||
buttonGroup.add(component)
|
||||
}
|
||||
|
||||
val cc = constraints?.create()?.let { lazyOf(it) } ?: lazy { CC() }
|
||||
createComponentConstraints(cc, component, gapLeft = gapLeft, growPolicy = growPolicy)
|
||||
|
||||
// JScrollPane doesn't have visual insets (not set by layout, but part of component implementation) as TextField, Combobox and other such components,
|
||||
// but it looks ugly, so, if not other components in the row and row is labeled - add left/right insets
|
||||
if (component is JScrollPane && labeled && components.size == 2 && !UIUtil.isUnderWin10LookAndFeel()) {
|
||||
val scrollPaneHGap = gapToBoundSize(4, true)
|
||||
cc.value.horizontal.gapBefore = scrollPaneHGap
|
||||
cc.value.horizontal.gapAfter = scrollPaneHGap
|
||||
}
|
||||
builder.defaultComponentConstraintCreator.createComponentConstraints(cc, component, gapLeft = gapLeft, growPolicy = growPolicy)
|
||||
|
||||
if (!noGrid && indent > 0 && components.size == 1) {
|
||||
cc.value.horizontal.gapBefore = gapToBoundSize(indent, true)
|
||||
}
|
||||
|
||||
if (!shareCellWithPreviousComponentIfNeed(component, cc)) {
|
||||
// increase column index if cell mode not enabled or it is a first component of cell
|
||||
if (componentIndexWhenCellModeWasEnabled == -1 || componentIndexWhenCellModeWasEnabled == (components.size - 1)) {
|
||||
columnIndex++
|
||||
}
|
||||
}
|
||||
|
||||
// if this row is not labeled and previous row is labeled and component is a "Remember" checkbox, skip one column (since this row doesn't have a label)
|
||||
if (!labeled && components.size == 1 && component is JCheckBox) {
|
||||
val siblings = parent!!.subRows
|
||||
@@ -240,9 +250,26 @@ internal class MigLayoutRow(private val parent: MigLayoutRow?,
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVisualPaddingsAndLabelTopGapIfNeed(component: JComponent) {
|
||||
if (!spacing.isCompensateVisualPaddings) {
|
||||
return
|
||||
}
|
||||
|
||||
val border = component.border
|
||||
if (border is LineBorder) {
|
||||
if (labeled && components.size == 2) {
|
||||
componentConstraints.get(components.first())?.vertical?.gapBefore = builder.defaultComponentConstraintCreator.vertical1pxGap
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val paddings = (border as? VisualPaddingsProvider)?.getVisualPaddings(component) ?: return
|
||||
component.putClientProperty(PlatformDefaults.VISUAL_PADDING_PROPERTY, paddings)
|
||||
}
|
||||
|
||||
private fun shareCellWithPreviousComponentIfNeed(component: JComponent, componentCC: Lazy<CC>): Boolean {
|
||||
if (components.size > 1 && component is JLabel && component.icon === AllIcons.General.Gear) {
|
||||
componentCC.value.horizontal.gapBefore = gapToBoundSize(0, true)
|
||||
componentCC.value.horizontal.gapBefore = builder.defaultComponentConstraintCreator.horizontalUnitSizeGap
|
||||
|
||||
if (lastComponentConstraintsWithSplit == null) {
|
||||
val prevComponent = components.get(components.size - 2)!!
|
||||
|
||||
+66
-70
@@ -20,15 +20,10 @@ import javax.swing.text.JTextComponent
|
||||
|
||||
internal fun Array<out CCFlags>.create() = if (isEmpty()) null else CC().apply(this)
|
||||
|
||||
private val SHORT_SHORT_TEXT_WIDTH = JBUI.scale(250)
|
||||
private val MAX_SHORT_TEXT_WIDTH = JBUI.scale(350)
|
||||
private val SHORT_TEXT_SIZE: BoundSize = ConstraintParser.parseBoundSize("${SHORT_SHORT_TEXT_WIDTH}px!", false, true)
|
||||
private val MEDIUM_TEXT_SIZE: BoundSize = ConstraintParser.parseBoundSize("${SHORT_SHORT_TEXT_WIDTH}px::${MAX_SHORT_TEXT_WIDTH}px", false, true)
|
||||
|
||||
private fun CC.apply(flags: Array<out CCFlags>): CC {
|
||||
for (flag in flags) {
|
||||
when (flag) {
|
||||
//CCFlags.wrap -> isWrap = true
|
||||
//CCFlags.wrap -> isWrap = true
|
||||
CCFlags.grow -> grow()
|
||||
CCFlags.growX -> {
|
||||
growX()
|
||||
@@ -39,90 +34,91 @@ private fun CC.apply(flags: Array<out CCFlags>): CC {
|
||||
// You can however accomplish the same thing by setting a gap before and/or after the components.
|
||||
// That gap may have a minimum size of 0 and a preferred size of a really large value to create a "pushing" gap.
|
||||
// There is even a keyword for this: "push". So "gapleft push" will be the same as "align right" and work for multi-component cells as well.
|
||||
//CCFlags.right -> horizontal.gapBefore = BoundSize(null, null, null, true, null)
|
||||
//CCFlags.right -> horizontal.gapBefore = BoundSize(null, null, null, true, null)
|
||||
|
||||
CCFlags.push -> push()
|
||||
CCFlags.pushX -> pushX()
|
||||
CCFlags.pushY -> pushY()
|
||||
|
||||
//CCFlags.span -> span()
|
||||
//CCFlags.spanX -> spanX()
|
||||
//CCFlags.spanY -> spanY()
|
||||
|
||||
//CCFlags.split -> split()
|
||||
|
||||
//CCFlags.skip -> skip()
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
internal fun createComponentConstraints(cc: Lazy<CC>,
|
||||
component: Component,
|
||||
gapLeft: Int = 0,
|
||||
gapAfter: Int = 0,
|
||||
gapTop: Int = 0,
|
||||
gapBottom: Int = 0,
|
||||
split: Int = -1,
|
||||
growPolicy: GrowPolicy?): CC? {
|
||||
if (gapLeft != 0) {
|
||||
cc.value.horizontal.gapBefore = gapToBoundSize(gapLeft, true)
|
||||
}
|
||||
if (gapAfter != 0) {
|
||||
cc.value.horizontal.gapAfter = gapToBoundSize(gapAfter, true)
|
||||
}
|
||||
internal class DefaultComponentConstraintCreator(private val spacing: SpacingConfiguration) {
|
||||
private val shortTextSizeSpec = ConstraintParser.parseBoundSize("${spacing.shortTextWidth}px!", false, true)
|
||||
private val mediumTextSizeSpec = ConstraintParser.parseBoundSize("${spacing.shortTextWidth}px::${spacing.maxShortTextWidth}px", false, true)
|
||||
|
||||
if (gapTop != 0) {
|
||||
cc.value.vertical.gapBefore = gapToBoundSize(gapTop, false)
|
||||
}
|
||||
if (gapBottom != 0) {
|
||||
cc.value.vertical.gapAfter = gapToBoundSize(gapBottom, false)
|
||||
}
|
||||
val vertical1pxGap: BoundSize = ConstraintParser.parseBoundSize("${JBUI.scale(1)}px!", true, false)
|
||||
|
||||
if (split != -1) {
|
||||
cc.value.split = split
|
||||
}
|
||||
val horizontalUnitSizeGap = gapToBoundSize(spacing.unitSize, true)
|
||||
|
||||
if (growPolicy != null) {
|
||||
applyGrowPolicy(cc.value, growPolicy)
|
||||
}
|
||||
else {
|
||||
addGrowIfNeed(cc, component)
|
||||
}
|
||||
|
||||
return if (cc.isInitialized()) cc.value else null
|
||||
}
|
||||
|
||||
private fun addGrowIfNeed(cc: Lazy<CC>, component: Component) {
|
||||
when {
|
||||
component is TextFieldWithHistory || component is TextFieldWithHistoryWithBrowseButton -> {
|
||||
// yes, no max width. approved by UI team (all path fields stretched to the width of the window)
|
||||
cc.value.minWidth("${MAX_SHORT_TEXT_WIDTH}px")
|
||||
cc.value.growX()
|
||||
fun createComponentConstraints(cc: Lazy<CC>,
|
||||
component: Component,
|
||||
gapLeft: Int = 0,
|
||||
gapAfter: Int = 0,
|
||||
gapTop: Int = 0,
|
||||
gapBottom: Int = 0,
|
||||
split: Int = -1,
|
||||
growPolicy: GrowPolicy?): CC? {
|
||||
if (gapLeft != 0) {
|
||||
cc.value.horizontal.gapBefore = gapToBoundSize(gapLeft, true)
|
||||
}
|
||||
if (gapAfter != 0) {
|
||||
cc.value.horizontal.gapAfter = gapToBoundSize(gapAfter, true)
|
||||
}
|
||||
|
||||
component is JPasswordField -> {
|
||||
applyGrowPolicy(cc.value, GrowPolicy.SHORT_TEXT)
|
||||
if (gapTop != 0) {
|
||||
cc.value.vertical.gapBefore = gapToBoundSize(gapTop, false)
|
||||
}
|
||||
if (gapBottom != 0) {
|
||||
cc.value.vertical.gapAfter = gapToBoundSize(gapBottom, false)
|
||||
}
|
||||
|
||||
component is JTextComponent || component is SeparatorComponent || component is ComponentWithBrowseButton<*> -> {
|
||||
cc.value.growX()
|
||||
if (split != -1) {
|
||||
cc.value.split = split
|
||||
}
|
||||
|
||||
component is JScrollPane ||
|
||||
(component is JPanel && component.componentCount == 1 && (component.getComponent(0) as? JComponent)?.getClientProperty(
|
||||
ActionToolbar.ACTION_TOOLBAR_PROPERTY_KEY) != null) -> {
|
||||
// no need to use pushX - default pushX for cell is 100. avoid to configure more than need
|
||||
cc.value
|
||||
.grow()
|
||||
.pushY()
|
||||
if (growPolicy != null) {
|
||||
applyGrowPolicy(cc.value, growPolicy)
|
||||
}
|
||||
else {
|
||||
addGrowIfNeed(cc, component, spacing)
|
||||
}
|
||||
|
||||
return if (cc.isInitialized()) cc.value else null
|
||||
}
|
||||
|
||||
private fun addGrowIfNeed(cc: Lazy<CC>, component: Component, spacing: SpacingConfiguration) {
|
||||
when {
|
||||
component is TextFieldWithHistory || component is TextFieldWithHistoryWithBrowseButton -> {
|
||||
// yes, no max width. approved by UI team (all path fields stretched to the width of the window)
|
||||
cc.value.minWidth("${spacing.maxShortTextWidth}px")
|
||||
cc.value.growX()
|
||||
}
|
||||
|
||||
component is JPasswordField -> {
|
||||
applyGrowPolicy(cc.value, GrowPolicy.SHORT_TEXT)
|
||||
}
|
||||
|
||||
component is JTextComponent || component is SeparatorComponent || component is ComponentWithBrowseButton<*> -> {
|
||||
cc.value.growX()
|
||||
}
|
||||
|
||||
component is JScrollPane ||
|
||||
(component is JPanel && component.componentCount == 1 && (component.getComponent(0) as? JComponent)?.getClientProperty(
|
||||
ActionToolbar.ACTION_TOOLBAR_PROPERTY_KEY) != null) -> {
|
||||
// no need to use pushX - default pushX for cell is 100. avoid to configure more than need
|
||||
cc.value
|
||||
.grow()
|
||||
.pushY()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyGrowPolicy(cc: CC, growPolicy: GrowPolicy) {
|
||||
cc.horizontal.size = when (growPolicy) {
|
||||
GrowPolicy.SHORT_TEXT -> SHORT_TEXT_SIZE
|
||||
GrowPolicy.MEDIUM_TEXT -> MEDIUM_TEXT_SIZE
|
||||
private fun applyGrowPolicy(cc: CC, growPolicy: GrowPolicy) {
|
||||
cc.horizontal.size = when (growPolicy) {
|
||||
GrowPolicy.SHORT_TEXT -> shortTextSizeSpec
|
||||
GrowPolicy.MEDIUM_TEXT -> mediumTextSizeSpec
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
# UI DSL
|
||||
|
||||
Use `panel` to create UI:
|
||||
|
||||
```kotlin
|
||||
|
||||
@@ -3,9 +3,9 @@ package com.intellij.ui.layout
|
||||
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.ui.JBIntSpinner
|
||||
import com.intellij.ui.components.CheckBox
|
||||
import com.intellij.ui.components.JBPasswordField
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.components.RadioButton
|
||||
import java.awt.Dimension
|
||||
import javax.swing.*
|
||||
@@ -23,7 +23,7 @@ fun makeSecondColumnSmaller(): JPanel {
|
||||
val branchCombobox = ComboBox<String>()
|
||||
val diffButton = JButton("Show Diff")
|
||||
|
||||
val titleTextField = JBTextField()
|
||||
val titleTextField = JTextField()
|
||||
|
||||
val descriptionTextArea = JTextArea()
|
||||
|
||||
@@ -33,8 +33,10 @@ fun makeSecondColumnSmaller(): JPanel {
|
||||
selectForkButton(growX)
|
||||
}
|
||||
row("Base branch:") {
|
||||
branchCombobox(growX, pushX)
|
||||
diffButton(growX)
|
||||
cell {
|
||||
branchCombobox(growX, pushX)
|
||||
diffButton(growX)
|
||||
}
|
||||
}
|
||||
row("Title:") { titleTextField() }
|
||||
row("Description:") {
|
||||
@@ -47,6 +49,50 @@ fun makeSecondColumnSmaller(): JPanel {
|
||||
return panel
|
||||
}
|
||||
|
||||
fun visualPaddingsPanelOnlyComboBox(): JPanel {
|
||||
return panel {
|
||||
row("Combobox:") { JComboBox<String>(arrayOf("one", "two"))(growX) }
|
||||
}
|
||||
}
|
||||
|
||||
fun visualPaddingsPanelOnlyButton(): JPanel {
|
||||
return panel {
|
||||
row("Button:") { button("label", growX) {} }
|
||||
}
|
||||
}
|
||||
|
||||
fun visualPaddingsPanel(): JPanel {
|
||||
// we use growX to test right border
|
||||
return panel {
|
||||
row("Text field:") { JTextField("text")() }
|
||||
row("Password:") { JPasswordField("secret")() }
|
||||
row("Combobox:") { JComboBox<String>(arrayOf("one", "two"))(growX) }
|
||||
row("Combobox Editable:") {
|
||||
val field = JComboBox<String>(arrayOf("one", "two"))
|
||||
field.isEditable = true
|
||||
field(growX)
|
||||
}
|
||||
row("Button:") { button("label", growX) {} }
|
||||
row("CheckBox:") { CheckBox("enabled")() }
|
||||
row("RadioButton:") { JRadioButton("label")() }
|
||||
row("Spinner:") { JBIntSpinner(0, 0, 7)() }
|
||||
// test text baseline alignment
|
||||
row("All:") {
|
||||
cell {
|
||||
JTextField("t")()
|
||||
JPasswordField("secret")()
|
||||
JComboBox<String>(arrayOf("c1", "c2"))(growX)
|
||||
button("b") {}
|
||||
CheckBox("c")()
|
||||
JRadioButton("rb")()
|
||||
}
|
||||
}
|
||||
row("Scroll pane:") {
|
||||
scrollPane(JTextArea("first line baseline equals to label"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun alignFieldsInTheNestedGrid(): JPanel {
|
||||
return panel {
|
||||
buttonGroup {
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
- {}
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 4.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- {}
|
||||
count: 4
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 6.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
- gapAfter:
|
||||
max: &id005 {horizontal: true, value: 8.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
In KeePass: {spanX: 2097051, wrap: true}
|
||||
'Database:':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id006 {horizontal: true, value: 21.0}
|
||||
preferred: *id006
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id007 {horizontal: false, value: 4.0}
|
||||
min: *id007
|
||||
preferred: *id007
|
||||
'JTextField #2':
|
||||
horizontal: {grow: 100.0}
|
||||
split: 2
|
||||
'JLabel #3':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id008 {horizontal: true, value: 4.0}
|
||||
preferred: *id008
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Master Password:':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id009 {horizontal: true, value: 21.0}
|
||||
preferred: *id009
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id010 {horizontal: false, value: 4.0}
|
||||
min: *id010
|
||||
preferred: *id010
|
||||
'JBPasswordField #5': {spanX: 2097051, wrap: true}
|
||||
Stored using weak encryption.:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id011 {horizontal: true, value: 1.0}
|
||||
preferred: *id011
|
||||
skip: 1
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 480, 24], [0, 34, 131, 24], [137, 34, 335, 24], [137, 34, 335,
|
||||
24], [0, 68, 131, 24], [137, 68, 343, 24], [137, 96, 343, 14]'
|
||||
@@ -0,0 +1,49 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 6.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 8.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
Create Android module:
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id005 {horizontal: false, value: 4.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
'Android module name:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id006 {horizontal: false, value: 4.0}
|
||||
min: *id006
|
||||
preferred: *id006
|
||||
'JTextField #3':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 142, 24], [148, 0, 332, 24], [0, 34, 142, 24], [148, 34, 332,
|
||||
24]'
|
||||
@@ -0,0 +1,67 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
gapAfter:
|
||||
max: &id003 {horizontal: true, value: 4.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- {}
|
||||
count: 2
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 6.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
- gapAfter:
|
||||
max: &id005 {horizontal: true, value: 8.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
'Repository:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id006 {horizontal: false, value: 4.0}
|
||||
min: *id006
|
||||
preferred: *id006
|
||||
'ComboBox #1': {split: 2}
|
||||
Delete:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id007 {horizontal: true, value: 8.0}
|
||||
preferred: *id007
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
Use File -> Settings Repository... to configure:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id008 {horizontal: true, value: 2.0}
|
||||
preferred: *id008
|
||||
skip: 1
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'JBScrollPane #4':
|
||||
horizontal: {grow: 100.0}
|
||||
pushY: 100.0
|
||||
spanX: 2097051
|
||||
vertical: {grow: 100.0}
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 70, 24], [76, 0, 396, 24], [76, 0, 396, 24], [76, 28, 404, 14],
|
||||
[0, 52, 480, 258]'
|
||||
@@ -0,0 +1,66 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
noGrid: true
|
||||
- {}
|
||||
- {}
|
||||
- {noGrid: true}
|
||||
count: 4
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 6.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 8.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
Profiler requires access to the kernel-level API. Enter the sudo password to allow this.:
|
||||
spanX: 2097051
|
||||
vertical:
|
||||
gapAfter:
|
||||
min: &id005 {horizontal: false, value: 20.0}
|
||||
preferred: *id005
|
||||
gapBefore:
|
||||
min: &id006 {horizontal: false, value: 10.0}
|
||||
preferred: *id006
|
||||
wrap: true
|
||||
'Sudo password:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id007 {horizontal: false, value: 4.0}
|
||||
min: *id007
|
||||
preferred: *id007
|
||||
'JPasswordField #2': {spanX: 2097051, wrap: true}
|
||||
!!binary "G1JlbWVtYmVy": {skip: 1, spanX: 2097051, wrap: true}
|
||||
'SimpleColoredComponent #4':
|
||||
spanX: 2097051
|
||||
vertical:
|
||||
gapAfter:
|
||||
min: &id008 {horizontal: false, value: 20.0}
|
||||
preferred: *id008
|
||||
gapBefore:
|
||||
min: &id009 {horizontal: false, value: 12.0}
|
||||
preferred: *id009
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 480, 62], [0, 72, 100, 24], [106, 72, 374, 24], [106, 106, 374,
|
||||
24], [0, 140, 480, 52]'
|
||||
@@ -0,0 +1,155 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 6.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 8.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
'Text field:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id005 {horizontal: false, value: 4.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
'JTextField #1':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Password:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id006 {horizontal: false, value: 4.0}
|
||||
min: *id006
|
||||
preferred: *id006
|
||||
'JPasswordField #3': {spanX: 2097051, wrap: true}
|
||||
'Combobox:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id007 {horizontal: false, value: 4.0}
|
||||
min: *id007
|
||||
preferred: *id007
|
||||
'JComboBox #5':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Combobox Editable:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id008 {horizontal: false, value: 4.0}
|
||||
min: *id008
|
||||
preferred: *id008
|
||||
'JComboBox #7':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Button:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id009 {horizontal: false, value: 4.0}
|
||||
min: *id009
|
||||
preferred: *id009
|
||||
label: {spanX: 2097051, wrap: true}
|
||||
'CheckBox:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id010 {horizontal: false, value: 4.0}
|
||||
min: *id010
|
||||
preferred: *id010
|
||||
enabled: {spanX: 2097051, wrap: true}
|
||||
'RadioButton:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id011 {horizontal: false, value: 4.0}
|
||||
min: *id011
|
||||
preferred: *id011
|
||||
'Spinner:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id012 {horizontal: false, value: 4.0}
|
||||
min: *id012
|
||||
preferred: *id012
|
||||
'JBIntSpinner #15': {spanX: 2097051, wrap: true}
|
||||
'All:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id013 {horizontal: false, value: 4.0}
|
||||
min: *id013
|
||||
preferred: *id013
|
||||
'JTextField #17':
|
||||
horizontal: {grow: 100.0}
|
||||
split: 6
|
||||
'JPasswordField #18':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id014 {horizontal: true, value: 8.0}
|
||||
preferred: *id014
|
||||
size:
|
||||
max: &id015 {horizontal: true, value: 250.0}
|
||||
min: *id015
|
||||
preferred: *id015
|
||||
'JComboBox #19':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id016 {horizontal: true, value: 8.0}
|
||||
preferred: *id016
|
||||
grow: 100.0
|
||||
b:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id017 {horizontal: true, value: 8.0}
|
||||
preferred: *id017
|
||||
c:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id018 {horizontal: true, value: 8.0}
|
||||
preferred: *id018
|
||||
rb:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id019 {horizontal: true, value: 8.0}
|
||||
preferred: *id019
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Scroll pane:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id020 {horizontal: false, value: 1.0}
|
||||
min: *id020
|
||||
preferred: *id020
|
||||
'JBScrollPane #24':
|
||||
horizontal: {grow: 100.0}
|
||||
pushY: 100.0
|
||||
spanX: 2097051
|
||||
vertical: {grow: 100.0}
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 124, 24], [130, 0, 518, 24], [0, 34, 124, 24], [130, 34, 518,
|
||||
24], [0, 68, 124, 24], [130, 68, 518, 24], [0, 102, 124, 24], [130, 102, 518, 24],
|
||||
[0, 136, 124, 24], [130, 136, 518, 24], [0, 170, 124, 24], [130, 170, 518, 24],
|
||||
[0, 204, 124, 24], [130, 204, 518, 24], [0, 238, 124, 24], [130, 238, 518, 24],
|
||||
[0, 272, 124, 24], [130, 272, 510, 24], [130, 272, 510, 24], [130, 272, 510, 24],
|
||||
[130, 272, 510, 24], [130, 272, 510, 24], [130, 272, 510, 24], [0, 306, 124, 21],
|
||||
[130, 306, 518, 21]'
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
- {}
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 4.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- {}
|
||||
count: 4
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 6.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
- gapAfter:
|
||||
max: &id005 {horizontal: true, value: 8.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
In KeePass: {spanX: 2097051, wrap: true}
|
||||
'Database:':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id006 {horizontal: true, value: 24.0}
|
||||
preferred: *id006
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id007 {horizontal: false, value: 2.0}
|
||||
min: *id007
|
||||
preferred: *id007
|
||||
'JTextField #2':
|
||||
horizontal: {grow: 100.0}
|
||||
split: 2
|
||||
'JLabel #3':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id008 {horizontal: true, value: 4.0}
|
||||
preferred: *id008
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Master Password:':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id009 {horizontal: true, value: 24.0}
|
||||
preferred: *id009
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id010 {horizontal: false, value: 2.0}
|
||||
min: *id010
|
||||
preferred: *id010
|
||||
'JBPasswordField #5': {spanX: 2097051, wrap: true}
|
||||
Stored using weak encryption.:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id011 {horizontal: true, value: 1.0}
|
||||
preferred: *id011
|
||||
skip: 1
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 480, 21], [0, 31, 134, 21], [140, 31, 332, 21], [140, 31, 332,
|
||||
21], [0, 62, 134, 21], [140, 62, 340, 21], [140, 87, 340, 14]'
|
||||
@@ -0,0 +1,49 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 6.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 8.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
Create Android module:
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id005 {horizontal: false, value: 2.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
'Android module name:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id006 {horizontal: false, value: 2.0}
|
||||
min: *id006
|
||||
preferred: *id006
|
||||
'JTextField #3':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 142, 21], [148, 0, 332, 21], [0, 31, 142, 21], [148, 31, 332,
|
||||
21]'
|
||||
@@ -0,0 +1,67 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
gapAfter:
|
||||
max: &id003 {horizontal: true, value: 4.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- {}
|
||||
count: 2
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 6.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
- gapAfter:
|
||||
max: &id005 {horizontal: true, value: 8.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
'Repository:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id006 {horizontal: false, value: 2.0}
|
||||
min: *id006
|
||||
preferred: *id006
|
||||
'ComboBox #1': {split: 2}
|
||||
Delete:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id007 {horizontal: true, value: 8.0}
|
||||
preferred: *id007
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
Use File -> Settings Repository... to configure:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id008 {horizontal: true, value: 2.0}
|
||||
preferred: *id008
|
||||
skip: 1
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'JBScrollPane #4':
|
||||
horizontal: {grow: 100.0}
|
||||
pushY: 100.0
|
||||
spanX: 2097051
|
||||
vertical: {grow: 100.0}
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 70, 21], [76, 0, 396, 21], [76, 0, 396, 21], [76, 25, 404, 14],
|
||||
[0, 49, 480, 261]'
|
||||
@@ -0,0 +1,66 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
noGrid: true
|
||||
- {}
|
||||
- {}
|
||||
- {noGrid: true}
|
||||
count: 4
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 6.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 8.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
Profiler requires access to the kernel-level API. Enter the sudo password to allow this.:
|
||||
spanX: 2097051
|
||||
vertical:
|
||||
gapAfter:
|
||||
min: &id005 {horizontal: false, value: 20.0}
|
||||
preferred: *id005
|
||||
gapBefore:
|
||||
min: &id006 {horizontal: false, value: 10.0}
|
||||
preferred: *id006
|
||||
wrap: true
|
||||
'Sudo password:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id007 {horizontal: false, value: 2.0}
|
||||
min: *id007
|
||||
preferred: *id007
|
||||
'JPasswordField #2': {spanX: 2097051, wrap: true}
|
||||
!!binary "G1JlbWVtYmVy": {skip: 1, spanX: 2097051, wrap: true}
|
||||
'SimpleColoredComponent #4':
|
||||
spanX: 2097051
|
||||
vertical:
|
||||
gapAfter:
|
||||
min: &id008 {horizontal: false, value: 20.0}
|
||||
preferred: *id008
|
||||
gapBefore:
|
||||
min: &id009 {horizontal: false, value: 12.0}
|
||||
preferred: *id009
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 480, 62], [0, 72, 100, 21], [106, 72, 374, 21], [106, 103, 374,
|
||||
21], [0, 134, 480, 52]'
|
||||
@@ -0,0 +1,155 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, unit: 0, value: 0.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, value: 10.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
- {horizontal: false, unit: 0, value: 0.0}
|
||||
- {horizontal: true, unit: 0, value: 0.0}
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, unit: 6, value: 0.0}
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, value: 6.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- gapAfter:
|
||||
max: &id004 {horizontal: true, value: 8.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
grow: 100.0
|
||||
- {}
|
||||
count: 3
|
||||
componentConstrains:
|
||||
'Text field:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id005 {horizontal: false, value: 2.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
'JTextField #1':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Password:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id006 {horizontal: false, value: 2.0}
|
||||
min: *id006
|
||||
preferred: *id006
|
||||
'JPasswordField #3': {spanX: 2097051, wrap: true}
|
||||
'Combobox:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id007 {horizontal: false, value: 2.0}
|
||||
min: *id007
|
||||
preferred: *id007
|
||||
'JComboBox #5':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Combobox Editable:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id008 {horizontal: false, value: 2.0}
|
||||
min: *id008
|
||||
preferred: *id008
|
||||
'JComboBox #7':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Button:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id009 {horizontal: false, value: 2.0}
|
||||
min: *id009
|
||||
preferred: *id009
|
||||
label: {spanX: 2097051, wrap: true}
|
||||
'CheckBox:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id010 {horizontal: false, value: 2.0}
|
||||
min: *id010
|
||||
preferred: *id010
|
||||
enabled: {spanX: 2097051, wrap: true}
|
||||
'RadioButton:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id011 {horizontal: false, value: 2.0}
|
||||
min: *id011
|
||||
preferred: *id011
|
||||
'Spinner:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id012 {horizontal: false, value: 2.0}
|
||||
min: *id012
|
||||
preferred: *id012
|
||||
'JBIntSpinner #15': {spanX: 2097051, wrap: true}
|
||||
'All:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id013 {horizontal: false, value: 2.0}
|
||||
min: *id013
|
||||
preferred: *id013
|
||||
'JTextField #17':
|
||||
horizontal: {grow: 100.0}
|
||||
split: 6
|
||||
'JPasswordField #18':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id014 {horizontal: true, value: 8.0}
|
||||
preferred: *id014
|
||||
size:
|
||||
max: &id015 {horizontal: true, value: 250.0}
|
||||
min: *id015
|
||||
preferred: *id015
|
||||
'JComboBox #19':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id016 {horizontal: true, value: 8.0}
|
||||
preferred: *id016
|
||||
grow: 100.0
|
||||
b:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id017 {horizontal: true, value: 8.0}
|
||||
preferred: *id017
|
||||
c:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id018 {horizontal: true, value: 8.0}
|
||||
preferred: *id018
|
||||
rb:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id019 {horizontal: true, value: 8.0}
|
||||
preferred: *id019
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Scroll pane:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id020 {horizontal: false, value: 1.0}
|
||||
min: *id020
|
||||
preferred: *id020
|
||||
'JBScrollPane #24':
|
||||
horizontal: {grow: 100.0}
|
||||
pushY: 100.0
|
||||
spanX: 2097051
|
||||
vertical: {grow: 100.0}
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 124, 21], [130, 0, 519, 21], [0, 31, 124, 21], [130, 31, 519,
|
||||
21], [0, 62, 124, 21], [130, 62, 519, 21], [0, 93, 124, 21], [130, 93, 519, 21],
|
||||
[0, 124, 124, 21], [130, 124, 519, 21], [0, 155, 124, 21], [130, 155, 519, 21],
|
||||
[0, 186, 124, 21], [130, 186, 519, 21], [0, 217, 124, 21], [130, 217, 519, 21],
|
||||
[0, 248, 124, 21], [130, 248, 511, 21], [130, 248, 511, 21], [130, 248, 511, 21],
|
||||
[130, 248, 511, 21], [130, 248, 511, 21], [130, 248, 511, 21], [0, 279, 124, 31],
|
||||
[130, 279, 519, 31]'
|
||||
@@ -1,63 +0,0 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 20.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
visualPadding: false
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, operation: 100, unit: 6, value: 0.0}
|
||||
- {}
|
||||
- gapAfter:
|
||||
max: &id003 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- {}
|
||||
count: 4
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- {}
|
||||
- {grow: 100.0}
|
||||
count: 2
|
||||
componentConstrains:
|
||||
In KeePass: {spanX: 2097051, wrap: true}
|
||||
'Database:':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id004 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 23.0}
|
||||
preferred: *id004
|
||||
'JTextField #2':
|
||||
horizontal: {grow: 100.0}
|
||||
split: 2
|
||||
'JLabel #3':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id005 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
preferred: *id005
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'Master Password:':
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id006 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 23.0}
|
||||
preferred: *id006
|
||||
'JBPasswordField #5': {spanX: 2097051, wrap: true}
|
||||
Stored using weak encryption.:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id007 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
preferred: *id007
|
||||
skip: 1
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 512, 23], [0, 27, 132, 26], [152, 27, 360, 26], [152, 27, 360,
|
||||
26], [0, 57, 132, 26], [152, 57, 360, 26], [152, 83, 360, 14]'
|
||||
@@ -1,39 +0,0 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 20.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
visualPadding: false
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, operation: 100, unit: 6, value: 0.0}
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- {}
|
||||
- {grow: 100.0}
|
||||
count: 2
|
||||
componentConstrains:
|
||||
Create Android module:
|
||||
vertical:
|
||||
gapBefore: &id004
|
||||
max: &id003 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
'Android module name:':
|
||||
vertical:
|
||||
gapBefore: *id004
|
||||
'JTextField #3':
|
||||
horizontal: {grow: 100.0}
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 145, 23], [165, 0, 347, 23], [0, 27, 145, 26], [165, 27, 347,
|
||||
26]'
|
||||
@@ -1,54 +0,0 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 20.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
visualPadding: false
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, operation: 100, unit: 6, value: 0.0}
|
||||
gapAfter:
|
||||
max: &id003 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
min: *id003
|
||||
preferred: *id003
|
||||
- {}
|
||||
count: 2
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- {}
|
||||
- {grow: 100.0}
|
||||
count: 2
|
||||
componentConstrains:
|
||||
'Repository:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id004 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
min: *id004
|
||||
preferred: *id004
|
||||
'ComboBox #1': {split: 2}
|
||||
Delete: {spanX: 2097051, wrap: true}
|
||||
Use File -> Settings Repository... to configure:
|
||||
horizontal:
|
||||
gapBefore:
|
||||
min: &id005 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
preferred: *id005
|
||||
skip: 1
|
||||
spanX: 2097051
|
||||
wrap: true
|
||||
'JBScrollPane #4':
|
||||
horizontal: {grow: 100.0}
|
||||
pushY: 100.0
|
||||
spanX: 2097051
|
||||
vertical: {grow: 100.0}
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 71, 29], [91, 0, 421, 29], [91, 0, 421, 29], [91, 29, 421, 14],
|
||||
[0, 47, 512, 205]'
|
||||
@@ -1,59 +0,0 @@
|
||||
layoutConstraints: !!net.miginfocom.layout.LC
|
||||
fillX: true
|
||||
gridGapX:
|
||||
min: &id001 {horizontal: true, operation: 100, unit: 0, unitString: px, value: 20.0}
|
||||
preferred: *id001
|
||||
gridGapY:
|
||||
min: &id002 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
preferred: *id002
|
||||
hideMode: 3
|
||||
insets:
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: false, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
- {horizontal: true, operation: 100, unit: 0, unitString: px, value: 0.0}
|
||||
visualPadding: false
|
||||
rowConstraints:
|
||||
constraints:
|
||||
- align: {horizontal: false, operation: 100, unit: 6, value: 0.0}
|
||||
noGrid: true
|
||||
- {}
|
||||
- {}
|
||||
- {noGrid: true}
|
||||
count: 4
|
||||
columnConstraints:
|
||||
constraints:
|
||||
- {}
|
||||
- {grow: 100.0}
|
||||
count: 2
|
||||
componentConstrains:
|
||||
Profiler requires access to the kernel-level API. Enter the sudo password to allow this.:
|
||||
spanX: 2097051
|
||||
vertical:
|
||||
gapAfter:
|
||||
min: &id003 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 10.0}
|
||||
preferred: *id003
|
||||
gapBefore:
|
||||
min: &id004 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
preferred: *id004
|
||||
wrap: true
|
||||
'Sudo password:':
|
||||
vertical:
|
||||
gapBefore:
|
||||
max: &id005 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 4.0}
|
||||
min: *id005
|
||||
preferred: *id005
|
||||
'JPasswordField #2': {spanX: 2097051, wrap: true}
|
||||
!!binary "G1JlbWVtYmVy": {skip: 1, spanX: 2097051, wrap: true}
|
||||
'SimpleColoredComponent #4':
|
||||
spanX: 2097051
|
||||
vertical:
|
||||
gapAfter:
|
||||
min: &id006 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 10.0}
|
||||
preferred: *id006
|
||||
gapBefore:
|
||||
min: &id007 {horizontal: false, operation: 100, unit: 0, unitString: px, value: 12.0}
|
||||
preferred: *id007
|
||||
wrap: true
|
||||
rectangles: '[0, 0, 512, 46], [0, 50, 99, 26], [119, 50, 393, 26], [119, 80, 393,
|
||||
23], [0, 107, 512, 42]'
|
||||
@@ -2,11 +2,15 @@
|
||||
package com.intellij.ui.layout
|
||||
|
||||
import com.intellij.ide.ui.laf.IntelliJLaf
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import com.intellij.ui.components.dialog
|
||||
import com.intellij.util.io.write
|
||||
import com.intellij.util.ui.JBUI
|
||||
import net.miginfocom.layout.LayoutUtil
|
||||
import net.miginfocom.swing.MigLayout
|
||||
import java.awt.Dimension
|
||||
import java.awt.GraphicsEnvironment
|
||||
import java.nio.file.Paths
|
||||
import javax.swing.UIManager
|
||||
import javax.swing.plaf.metal.MetalLookAndFeel
|
||||
@@ -14,13 +18,23 @@ import javax.swing.plaf.metal.MetalLookAndFeel
|
||||
object MigLayoutTestApp {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
// LayoutUtil.setGlobalDebugMillis(1000)
|
||||
val isDebugEnabled = true
|
||||
// val isDebugEnabled = false
|
||||
@Suppress("ConstantConditionIf")
|
||||
if (isDebugEnabled) {
|
||||
LayoutUtil.setGlobalDebugMillis(1000)
|
||||
}
|
||||
|
||||
runInEdtAndWait {
|
||||
UIManager.setLookAndFeel(MetalLookAndFeel())
|
||||
UIManager.setLookAndFeel(IntelliJLaf())
|
||||
// UIManager.setLookAndFeel(IntelliJLaf())
|
||||
UIManager.setLookAndFeel(DarculaLaf())
|
||||
|
||||
// val panel = visualPaddingsPanelOnlyButton()
|
||||
// val panel = alignFieldsInTheNestedGrid()
|
||||
// val panel = cellPanel()
|
||||
val panel = visualPaddingsPanel()
|
||||
|
||||
val panel = noteRowInTheDialog()
|
||||
val dialog = dialog(
|
||||
title = "",
|
||||
panel = panel,
|
||||
@@ -30,9 +44,23 @@ object MigLayoutTestApp {
|
||||
return@dialog null
|
||||
}
|
||||
|
||||
panel.preferredSize = Dimension(512, 256)
|
||||
dialog.toFront()
|
||||
panel.preferredSize = Dimension(50, 50)
|
||||
Paths.get(System.getProperty("user.home"), "layout-dump.yml").write(configurationToJson(panel, panel.layout as MigLayout))
|
||||
|
||||
val screenDevices = GraphicsEnvironment.getLocalGraphicsEnvironment().screenDevices
|
||||
if (SystemInfoRt.isMac && screenDevices != null && screenDevices.size > 1) {
|
||||
// use not-Retina
|
||||
for (screenDevice in screenDevices) {
|
||||
if (!JBUI.isRetina(screenDevice)) {
|
||||
val screenBounds = screenDevice.defaultConfiguration.bounds
|
||||
dialog.setLocation(screenBounds.x, (screenBounds.height - dialog.preferredSize.height) / 2)
|
||||
dialog.window.setLocation(screenBounds.x, (screenBounds.height - dialog.preferredSize.height) / 2)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dialog.toFront()
|
||||
dialog.showAndGet()
|
||||
|
||||
// val frame = JFrame()
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
package com.intellij.ui.layout
|
||||
|
||||
import com.intellij.ide.ui.laf.IntelliJLaf
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaLaf
|
||||
import com.intellij.openapi.application.invokeAndWaitIfNeed
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.testFramework.assertions.Assertions
|
||||
@@ -10,23 +12,26 @@ import com.intellij.util.io.exists
|
||||
import com.intellij.util.io.outputStream
|
||||
import com.intellij.util.io.sanitizeFileName
|
||||
import com.intellij.util.io.write
|
||||
import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import io.netty.util.internal.SystemPropertyUtil
|
||||
import net.miginfocom.layout.Grid
|
||||
import net.miginfocom.layout.LayoutUtil
|
||||
import net.miginfocom.swing.MigLayout
|
||||
import org.assertj.core.data.Offset
|
||||
import org.assertj.swing.assertions.Assertions.assertThat
|
||||
import org.assertj.swing.edt.FailOnThreadViolationRepaintManager
|
||||
import org.assertj.swing.edt.GuiActionRunner
|
||||
import org.assertj.swing.fixture.FrameFixture
|
||||
import org.junit.*
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestName
|
||||
import java.awt.*
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Component
|
||||
import java.awt.Dimension
|
||||
import java.awt.GraphicsEnvironment
|
||||
import java.awt.image.BufferedImage
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.util.concurrent.Callable
|
||||
import javax.imageio.ImageIO
|
||||
import javax.swing.JFrame
|
||||
import javax.swing.JPanel
|
||||
@@ -40,84 +45,103 @@ import kotlin.properties.Delegates
|
||||
* Checkout git@github.com:develar/intellij-ui-dsl-test-snapshots.git (or create own repo) to some local dir and set env LAYOUT_IMAGE_REPO
|
||||
* to use image snapshots.
|
||||
*/
|
||||
class UiDslTest {
|
||||
open class UiDslTest {
|
||||
companion object {
|
||||
@Suppress("unused")
|
||||
@BeforeClass
|
||||
fun setUpOnce() {
|
||||
FailOnThreadViolationRepaintManager.install()
|
||||
UIManager.setLookAndFeel(MetalLookAndFeel())
|
||||
UIManager.setLookAndFeel(IntelliJLaf())
|
||||
}
|
||||
var currentLaf: String? = null
|
||||
|
||||
private val imageDir: String? = System.getenv("LAYOUT_IMAGE_REPO")
|
||||
}
|
||||
|
||||
private var window: FrameFixture by Delegates.notNull()
|
||||
open val lafName = "IntelliJ"
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val testName = TestName()
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
window.cleanUp()
|
||||
}
|
||||
|
||||
@Before
|
||||
fun beforeMethod() {
|
||||
assumeTrue(!UsefulTestCase.IS_UNDER_TEAMCITY)
|
||||
}
|
||||
|
||||
private fun saveImage(file: Path) {
|
||||
file.outputStream().use {
|
||||
ImageIO.write(componentToImage(getContentPane()), "png", it)
|
||||
if (currentLaf != lafName) {
|
||||
currentLaf = lafName
|
||||
invokeAndWaitIfNeed {
|
||||
UIManager.setLookAndFeel(MetalLookAndFeel())
|
||||
val laf = if (lafName == "IntelliJ") IntelliJLaf() else DarculaLaf()
|
||||
UIManager.setLookAndFeel(laf)
|
||||
|
||||
if (lafName == "Darcula") {
|
||||
// static init it is hell - UIUtil static init is called too early, so, call it to init properly
|
||||
// (otherwise null stylesheet added and it leads to NPE on set comment text)
|
||||
UIManager.getDefaults().put("javax.swing.JLabel.userStyleSheet", UIUtil.JBHtmlEditorKit.createStyleSheet())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getContentPane(): Container {
|
||||
return window.target()
|
||||
private fun saveImage(file: Path, component: Component) {
|
||||
file.outputStream().use {
|
||||
ImageIO.write(componentToImage(component), "png", it)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `align fields in the nested grid`() {
|
||||
doTest(alignFieldsInTheNestedGrid())
|
||||
doTest { alignFieldsInTheNestedGrid() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `align fields`() {
|
||||
doTest(labelRowShouldNotGrow())
|
||||
doTest { labelRowShouldNotGrow() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cell() {
|
||||
doTest(cellPanel())
|
||||
doTest { cellPanel() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `note row in the dialog`() {
|
||||
doTest(noteRowInTheDialog())
|
||||
doTest { noteRowInTheDialog() }
|
||||
}
|
||||
|
||||
private fun doTest(panel: JPanel) {
|
||||
val frame = GuiActionRunner.execute(Callable {
|
||||
@Test
|
||||
fun `visual paddings`() {
|
||||
doTest { visualPaddingsPanel()}
|
||||
}
|
||||
|
||||
private fun doTest(panelCreator: () -> JPanel) {
|
||||
var panel: JPanel by Delegates.notNull()
|
||||
val frame = invokeAndWaitIfNeed {
|
||||
LayoutUtil.setGlobalDebugMillis(1000)
|
||||
|
||||
panel.background = Color.WHITE
|
||||
panel.name = "test"
|
||||
panel = panelCreator()
|
||||
|
||||
val frame = JFrame("wrapper")
|
||||
frame.isUndecorated = true
|
||||
frame.contentPane.background = Color.WHITE
|
||||
frame.background = Color.WHITE
|
||||
frame.contentPane.add(panel, BorderLayout.CENTER)
|
||||
frame.minimumSize = Dimension(512, 256)
|
||||
frame
|
||||
})
|
||||
window = FrameFixture(frame)
|
||||
window.show()
|
||||
frame.minimumSize = Dimension(480, 320)
|
||||
|
||||
val component = window.panel("test").target() as JPanel
|
||||
val screenDevices = GraphicsEnvironment.getLocalGraphicsEnvironment().screenDevices
|
||||
if (SystemInfoRt.isMac && screenDevices != null && screenDevices.size > 1) {
|
||||
// use non-Retina
|
||||
for (screenDevice in screenDevices) {
|
||||
if (!JBUI.isRetina(screenDevice)) {
|
||||
frame.setLocation(screenDevice.defaultConfiguration.bounds.x, frame.y)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame.pack()
|
||||
frame.isVisible = true
|
||||
|
||||
// clear focus from first input field
|
||||
frame.requestFocusInWindow()
|
||||
|
||||
frame
|
||||
}
|
||||
|
||||
val component = panel
|
||||
val layout = component.layout as MigLayout
|
||||
|
||||
val gridField = MigLayout::class.java.getDeclaredField("grid")
|
||||
@@ -126,38 +150,40 @@ class UiDslTest {
|
||||
val rectangles = MigLayoutTestUtil.getRectangles(grid)
|
||||
|
||||
val imageName = sanitizeFileName(testName.methodName)
|
||||
val actualLayoutJson = configurationToJson(component, component.layout as MigLayout,
|
||||
rectangles.joinToString(", ") { "[${it.joinToString(", ")}]" })
|
||||
val actualSerializedLayout = configurationToJson(component, component.layout as MigLayout,
|
||||
rectangles.joinToString(", ") { "[${it.joinToString(", ")}]" })
|
||||
try {
|
||||
val expectedLayoutDataFile = Paths.get(PlatformTestUtil.getPlatformTestDataPath(), "ui", "layout", "$imageName.yml")
|
||||
val expectedLayoutDataFile = Paths.get(PlatformTestUtil.getPlatformTestDataPath(), "ui", "layout", lafName, "$imageName.yml")
|
||||
val isUpdateSnapshots = SystemPropertyUtil.getBoolean("test.update.snapshots", false)
|
||||
if (!expectedLayoutDataFile.exists() || isUpdateSnapshots) {
|
||||
expectedLayoutDataFile.write(actualLayoutJson)
|
||||
expectedLayoutDataFile.write(actualSerializedLayout)
|
||||
}
|
||||
else {
|
||||
Assertions.assertThat(actualLayoutJson).isEqualTo(expectedLayoutDataFile)
|
||||
Assertions.assertThat(actualSerializedLayout).isEqualTo(expectedLayoutDataFile)
|
||||
}
|
||||
|
||||
if (imageDir.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val imagePath = Paths.get(imageDir, "$imageName.png")
|
||||
val imagePath = Paths.get(imageDir, lafName, "$imageName.png")
|
||||
if (!imagePath.exists()) {
|
||||
System.out.println("Write a new snapshot image ${imagePath.fileName}")
|
||||
saveImage(imagePath)
|
||||
saveImage(imagePath, frame)
|
||||
return
|
||||
}
|
||||
|
||||
val newImage = ImageIO.read(imagePath.toFile())
|
||||
@Suppress("UnnecessaryVariable")
|
||||
val snapshotComponent = frame
|
||||
try {
|
||||
assertThat(componentToImage(getContentPane())).isEqualTo(newImage, Offset.offset(32))
|
||||
assertThat(componentToImage(snapshotComponent)).isEqualTo(newImage, Offset.offset(8))
|
||||
}
|
||||
catch (e: AssertionError) {
|
||||
if (isUpdateSnapshots) {
|
||||
System.out.println("UPDATED snapshot image ${imagePath.fileName}")
|
||||
imagePath.outputStream().use {
|
||||
ImageIO.write(componentToImage(getContentPane()), "png", it)
|
||||
ImageIO.write(componentToImage(snapshotComponent), "png", it)
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -167,14 +193,21 @@ class UiDslTest {
|
||||
}
|
||||
catch (e: AssertionError) {
|
||||
if (!imageDir.isNullOrEmpty()) {
|
||||
Paths.get(imageDir, "$imageName-NEW.yml").write(actualLayoutJson)
|
||||
saveImage(Paths.get(imageDir, "$imageName-NEW.png"))
|
||||
Paths.get(imageDir, "$imageName-NEW.yml").write(actualSerializedLayout)
|
||||
saveImage(Paths.get(imageDir, "$imageName-NEW.png"), frame)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
frame.isVisible = false
|
||||
frame.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
class DarculaUiDslTest : UiDslTest() {
|
||||
override val lafName = "Darcula"
|
||||
}
|
||||
|
||||
private fun componentToImage(component: Component, type: Int = BufferedImage.TYPE_BYTE_GRAY): BufferedImage {
|
||||
return invokeAndWaitIfNeed {
|
||||
// we don't need retina image
|
||||
|
||||
@@ -34,6 +34,24 @@ private val filter by lazy {
|
||||
if (bean is BoundSize && property.name == "unset") {
|
||||
return null
|
||||
}
|
||||
if (bean is UnitValue) {
|
||||
if (property.name == "unitString") {
|
||||
if (propertyValue != "px" && bean.value != 0f) {
|
||||
throw RuntimeException("Only px must be used")
|
||||
}
|
||||
return null
|
||||
}
|
||||
if (property.name == "unit" && bean.value != 0f) {
|
||||
if (propertyValue != UnitValue.PIXEL) {
|
||||
throw RuntimeException("Only px must be used")
|
||||
}
|
||||
return null
|
||||
}
|
||||
if (property.name == "operation" && propertyValue == 100) {
|
||||
// ignore static operation
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
val emptyBean = when (bean) {
|
||||
is AC -> emptyAC
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.ScalableIcon;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.SystemInfoRt;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.border.CustomLineBorder;
|
||||
import com.intellij.util.LazyInitializer.NotNullValue;
|
||||
@@ -41,6 +42,7 @@ public class JBUI {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.util.ui.JBUI");
|
||||
|
||||
public static final String USER_SCALE_FACTOR_PROPERTY = "JBUI.userScaleFactor";
|
||||
public static final String COMPENSATE_VISUAL_PADDING_KEY = "compensate.visual.padding";
|
||||
|
||||
private static final PropertyChangeSupport PCS = new PropertyChangeSupport(new JBUI());
|
||||
|
||||
@@ -306,6 +308,10 @@ public class JBUI {
|
||||
return sysScale();
|
||||
}
|
||||
|
||||
public static boolean isRetina(@NotNull GraphicsDevice device) {
|
||||
return UIUtil.DetectRetinaKit.isOracleMacRetinaDevice(device);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the system scale factor, corresponding to the graphics.
|
||||
* For BufferedImage's graphics, the scale is taken from the graphics itself.
|
||||
@@ -490,6 +496,7 @@ public class JBUI {
|
||||
return new JBDimension(size.width, size.height);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JBInsets insets(int top, int left, int bottom, int right) {
|
||||
return new JBInsets(top, left, bottom, right);
|
||||
}
|
||||
@@ -1429,7 +1436,7 @@ public class JBUI {
|
||||
return color == null ? defaultColor : color;
|
||||
}
|
||||
|
||||
private static int getInt(String propertyName, int defaultValue) {
|
||||
public static int getInt(String propertyName, int defaultValue) {
|
||||
Object value = UIManager.get(propertyName);
|
||||
return value instanceof Integer ? (Integer)value : defaultValue;
|
||||
}
|
||||
@@ -1438,4 +1445,22 @@ public class JBUI {
|
||||
Icon icon = UIManager.getIcon(propertyName);
|
||||
return icon == null ? defaultIcon : icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temp method to not break IDEA LaF until changes are not reviewed.
|
||||
*
|
||||
* Correct input size is used now only for UI DSL.
|
||||
*/
|
||||
public static boolean isUseCorrectInputHeightOnMacOS(@NotNull Component component) {
|
||||
if (!SystemInfoRt.isMac) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Container parent = component.getParent();
|
||||
return !isCompensateVisualPaddingOnComponentLevel(parent instanceof JComboBox ? parent.getParent() : parent);
|
||||
}
|
||||
|
||||
public static boolean isCompensateVisualPaddingOnComponentLevel(@Nullable Component parent) {
|
||||
return !(SystemInfoRt.isMac && parent instanceof JPanel && ((JPanel)parent).getClientProperty(COMPENSATE_VISUAL_PADDING_KEY) == Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user