mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-160020 Editor Search and Replace UI: switching to multiline mode (stage 2: main changes)
This commit is contained in:
@@ -39,7 +39,6 @@ import com.intellij.ui.components.panels.NonOpaquePanel;
|
||||
import com.intellij.ui.components.panels.Wrapper;
|
||||
import com.intellij.ui.speedSearch.SpeedSearchSupply;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -52,11 +51,11 @@ import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.EventListener;
|
||||
import java.util.List;
|
||||
|
||||
public class SearchReplaceComponent extends EditorHeaderComponent implements DataProvider {
|
||||
static final KeyStroke NEW_LINE_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
|
||||
private final EventDispatcher<Listener> myEventDispatcher = EventDispatcher.create(Listener.class);
|
||||
|
||||
private final MyTextComponentWrapper mySearchFieldWrapper;
|
||||
@@ -182,6 +181,7 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
myRightPanel.add(myReplaceToolbarWrapper, BorderLayout.CENTER);
|
||||
|
||||
OnePixelSplitter splitter = new OnePixelSplitter(false, .25F);
|
||||
myRightPanel.setBorder(JBUI.Borders.emptyLeft(6));
|
||||
splitter.setFirstComponent(myLeftPanel);
|
||||
splitter.setSecondComponent(myRightPanel);
|
||||
splitter.setHonorComponentsMinimumSize(true);
|
||||
@@ -215,7 +215,7 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
}
|
||||
}
|
||||
|
||||
public void requestFocusInTheSearchFieldAndSelectContent (Project project) {
|
||||
public void requestFocusInTheSearchFieldAndSelectContent(Project project) {
|
||||
mySearchTextComponent.setSelectionStart(0);
|
||||
mySearchTextComponent.setSelectionEnd(mySearchTextComponent.getText().length());
|
||||
IdeFocusManager.getInstance(project).requestFocus(mySearchTextComponent, true);
|
||||
@@ -237,7 +237,7 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (myCloseAction != null ) {
|
||||
if (myCloseAction != null) {
|
||||
myCloseAction.run();
|
||||
}
|
||||
}
|
||||
@@ -389,7 +389,8 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
if (needToResetReplaceFocus) {
|
||||
myReplaceTextComponent.requestFocusInWindow();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (myReplaceFieldWrapper.getParent() != null) {
|
||||
myLeftPanel.remove(myReplaceFieldWrapper);
|
||||
}
|
||||
@@ -420,7 +421,8 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
if (mySearchFieldWrapper.getTargetComponent() instanceof SearchTextField) {
|
||||
((SearchTextField)mySearchFieldWrapper.getTargetComponent()).addCurrentTextToHistory();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
findInProjectSettings.addStringToReplace(text);
|
||||
if (myReplaceFieldWrapper.getTargetComponent() instanceof SearchTextField) {
|
||||
((SearchTextField)myReplaceFieldWrapper.getTargetComponent()).addCurrentTextToHistory();
|
||||
@@ -433,45 +435,17 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
JTextComponent oldComponent = search ? mySearchTextComponent : myReplaceTextComponent;
|
||||
Color oldBackground = oldComponent != null ? oldComponent.getBackground() : null;
|
||||
final MyTextComponentWrapper wrapper = search ? mySearchFieldWrapper : myReplaceFieldWrapper;
|
||||
if (isMultiline() && oldComponent instanceof JTextArea) return false;
|
||||
if (!isMultiline() && oldComponent instanceof JTextField) return false;
|
||||
if (oldComponent != null) return false;
|
||||
|
||||
final JTextComponent textComponent;
|
||||
if (isMultiline()) {
|
||||
SearchTextArea textArea = new SearchTextArea(search);
|
||||
textComponent = textArea.getTextArea();
|
||||
((JTextArea)textComponent).setColumns(25);
|
||||
((JTextArea)textComponent).setRows(2);
|
||||
((JTextArea)textComponent).setRows(isMultiline() ? 2 : 1);
|
||||
KeymapUtil.reassignAction(textComponent,
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
|
||||
NEW_LINE_KEYSTROKE,
|
||||
WHEN_FOCUSED);
|
||||
wrapper.setContent(textArea);
|
||||
}
|
||||
else {
|
||||
SearchTextField searchTextField = new SearchTextField(true) {
|
||||
@Override
|
||||
protected boolean toClearTextOnEscape() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
searchTextField.setOpaque(false);
|
||||
textComponent = searchTextField.getTextEditor();
|
||||
searchTextField.getTextEditor().setColumns(25);
|
||||
if (UIUtil.isUnderGTKLookAndFeel()) {
|
||||
textComponent.setOpaque(false);
|
||||
}
|
||||
searchTextField.setHistorySize(20);
|
||||
FindInProjectSettings findInProjectSettings = FindInProjectSettings.getInstance(myProject);
|
||||
|
||||
searchTextField.setHistory(ContainerUtil.reverse(Arrays.asList(search ? findInProjectSettings.getRecentFindStrings()
|
||||
: findInProjectSettings.getRecentReplaceStrings())));
|
||||
textComponent.registerKeyboardAction(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
final String text = textComponent.getText();
|
||||
setMultilineInternal(true);
|
||||
ApplicationManager.getApplication().invokeLater(() -> ObjectUtils.assertNotNull(wrapper.getTextComponent()).setText(text + "\n"));
|
||||
}
|
||||
}, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.ALT_DOWN_MASK), JComponent.WHEN_FOCUSED);
|
||||
wrapper.setContent(searchTextField);
|
||||
}
|
||||
|
||||
UIUtil.addUndoRedoActions(textComponent);
|
||||
Utils.setSmallerFont(textComponent);
|
||||
@@ -514,7 +488,7 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
}
|
||||
|
||||
private static void adjustRows(@NotNull JTextArea area) {
|
||||
area.setRows(Math.max(2, Math.min(3, StringUtil.countChars(area.getText(),'\n')+1)));
|
||||
area.setRows(Math.max(2, Math.min(3, StringUtil.countChars(area.getText(), '\n') + 1)));
|
||||
}
|
||||
|
||||
|
||||
@@ -637,12 +611,12 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat
|
||||
private Runnable myReplaceAction;
|
||||
private Runnable myCloseAction;
|
||||
|
||||
private DefaultActionGroup mySearchActions = new DefaultActionGroup("search bar 1", false);
|
||||
private DefaultActionGroup mySearchActions = new DefaultActionGroup("search bar 1", false);
|
||||
private DefaultActionGroup myExtraSearchActions = new DefaultActionGroup("search bar 2", false);
|
||||
private DefaultActionGroup mySearchFieldActions = new DefaultActionGroup("search field actions", false);
|
||||
private BooleanGetter mySearchToolbarModifiedFlagGetter = BooleanGetter.FALSE;
|
||||
|
||||
private DefaultActionGroup myReplaceActions = new DefaultActionGroup("replace bar 1", false);
|
||||
private DefaultActionGroup myReplaceActions = new DefaultActionGroup("replace bar 1", false);
|
||||
private DefaultActionGroup myExtraReplaceActions = new DefaultActionGroup("replace bar 1", false);
|
||||
private DefaultActionGroup myReplaceFieldActions = new DefaultActionGroup("replace field actions", false);
|
||||
|
||||
|
||||
@@ -17,16 +17,20 @@ package com.intellij.find;
|
||||
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.find.editorHeaderActions.Utils;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
import com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet;
|
||||
import com.intellij.openapi.actionSystem.KeyboardShortcut;
|
||||
import com.intellij.ide.ui.laf.intellij.MacIntelliJIconCache;
|
||||
import com.intellij.ide.ui.laf.intellij.MacIntelliJTextFieldUI;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.impl.ActionButton;
|
||||
import com.intellij.openapi.actionSystem.impl.InplaceActionButtonLook;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
@@ -34,57 +38,119 @@ import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.components.panels.NonOpaquePanel;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import java.awt.*;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
public class SearchTextArea extends NonOpaquePanel implements PropertyChangeListener, FocusListener {
|
||||
private final JTextArea myTextArea;
|
||||
private final boolean myInfoMode;
|
||||
private final JLabel myInfoLabel;
|
||||
private JPanel myIconsPanel = null;
|
||||
private ActionButton myNewLineButton;
|
||||
private ActionButton myClearButton;
|
||||
private JBScrollPane myScrollPane;
|
||||
|
||||
public SearchTextArea(boolean search) {
|
||||
this(new JTextArea(), search);
|
||||
this(new JTextArea(), search, false);
|
||||
}
|
||||
|
||||
public SearchTextArea(@NotNull JTextArea textArea,boolean search) {
|
||||
public SearchTextArea(@NotNull JTextArea textArea, boolean search, boolean infoMode) {
|
||||
myTextArea = textArea;
|
||||
myInfoMode = infoMode;
|
||||
myTextArea.addPropertyChangeListener("background", this);
|
||||
myTextArea.addFocusListener(this);
|
||||
myTextArea.getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
updateIconsLayout();
|
||||
}
|
||||
});
|
||||
myTextArea.setBorder(null);
|
||||
myTextArea.setOpaque(false);
|
||||
JBScrollPane scrollPane = new JBScrollPane(myTextArea,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.getVerticalScrollBar().setBackground(UIUtil.TRANSPARENT_COLOR);
|
||||
scrollPane.getViewport().setBorder(null);
|
||||
scrollPane.getViewport().setOpaque(false);
|
||||
scrollPane.setBorder(JBUI.Borders.emptyRight(2));
|
||||
scrollPane.setOpaque(false);
|
||||
ShowHistoryAction historyAction = new ShowHistoryAction(search);
|
||||
ActionButton button =
|
||||
new ActionButton(historyAction, historyAction.getTemplatePresentation(), ActionPlaces.UNKNOWN, new Dimension(JBUI.scale(16), JBUI.scale(16)));
|
||||
button.setLook(new InplaceActionButtonLook());
|
||||
myScrollPane = new JBScrollPane(myTextArea,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED) {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension d = super.getPreferredSize();
|
||||
d.height = Math.min(d.height, myTextArea.getUI().getPreferredSize(myTextArea).height);
|
||||
return d;
|
||||
}
|
||||
};
|
||||
myScrollPane.getVerticalScrollBar().setBackground(UIUtil.TRANSPARENT_COLOR);
|
||||
myScrollPane.getViewport().setBorder(null);
|
||||
myScrollPane.getViewport().setOpaque(false);
|
||||
myScrollPane.setBorder(JBUI.Borders.emptyRight(2));
|
||||
myScrollPane.setOpaque(false);
|
||||
|
||||
myInfoLabel = new JBLabel(UIUtil.ComponentStyle.SMALL);
|
||||
myInfoLabel.setForeground(JBColor.GRAY);
|
||||
|
||||
setBorder(JBUI.Borders.empty(6, 6, 6, 8));
|
||||
setLayout(new MigLayout("flowx, ins 0, gapx " + JBUI.scale(4) + "px"));
|
||||
add(button, "ay top, gaptop " + JBUI.scale(2) + "px");
|
||||
add(scrollPane, "growx, pushx");
|
||||
add(myInfoLabel, "ay top, gaptop " + JBUI.scale(2) + "px, gapright " + JBUI.scale(6) + "px");
|
||||
setBorder(JBUI.Borders.empty(7, 6, 3, 6));
|
||||
setLayout(new MigLayout("flowx, ins 0 1 0 0, gapx " + JBUI.scale(4)));
|
||||
add(createButton(new ShowHistoryAction(search)), "ay top");
|
||||
add(myScrollPane, "growx, pushx, shrinky, gaptop " + JBUI.scale(1));
|
||||
if (myInfoMode) {
|
||||
add(myInfoLabel, "ay top, gaptop " + JBUI.scale(2));
|
||||
}
|
||||
else {
|
||||
myClearButton = createButton(new ClearAction());
|
||||
myNewLineButton = createButton(new NewLineAction());
|
||||
myIconsPanel = new NonOpaquePanel();
|
||||
add(myIconsPanel, "ay top, gaptop " + JBUI.scale(0));
|
||||
updateIconsLayout();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isNewLineAvailable() {
|
||||
return Registry.is("ide.find.show.add.newline.hint");
|
||||
}
|
||||
|
||||
private void updateIconsLayout() {
|
||||
if (myIconsPanel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean showClearIcon = !StringUtil.isEmpty(myTextArea.getText());
|
||||
boolean showNewLine = isNewLineAvailable();
|
||||
boolean wrongVisibility =
|
||||
((myClearButton.getParent() != null) != showClearIcon) || ((myNewLineButton.getParent() != null) != showNewLine);
|
||||
|
||||
LayoutManager layout = myIconsPanel.getLayout();
|
||||
boolean wrongLayout = !(layout instanceof GridLayout);
|
||||
boolean multiline = StringUtil.getLineBreakCount(myTextArea.getText()) > 0;
|
||||
boolean wrongPositioning = !wrongLayout && (((GridLayout)layout).getRows() > 1) != multiline;
|
||||
if (wrongLayout || wrongVisibility || wrongPositioning) {
|
||||
myIconsPanel.removeAll();
|
||||
int rows = multiline && showClearIcon && showNewLine ? 2 : 1;
|
||||
int columns = !multiline && showClearIcon && showNewLine ? 2 : 1;
|
||||
myIconsPanel.setLayout(new GridLayout(rows, columns, 8, 8));
|
||||
if (!multiline && showNewLine) {
|
||||
myIconsPanel.add(myNewLineButton);
|
||||
}
|
||||
if (showClearIcon) {
|
||||
myIconsPanel.add(myClearButton);
|
||||
}
|
||||
if (multiline && showNewLine) {
|
||||
myIconsPanel.add(myNewLineButton);
|
||||
}
|
||||
myScrollPane.revalidate();
|
||||
doLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public JTextArea getTextArea() {
|
||||
return myTextArea;
|
||||
@@ -121,21 +187,22 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
|
||||
Rectangle r = new Rectangle(getSize());
|
||||
r.x += JBUI.scale(4);
|
||||
r.y += JBUI.scale(3);
|
||||
r.width -= JBUI.scale(9);
|
||||
r.height -= JBUI.scale(6);
|
||||
int arcSize = Math.min(25, r.height - 1) - 6;
|
||||
g.setColor(myTextArea.getBackground());
|
||||
if (r.height % 2 == 1) r.height--;
|
||||
int arcSize = Math.min(25, r.height-1);
|
||||
boolean hasFocus = myTextArea.hasFocus();
|
||||
g.fillRoundRect(r.x, r.y + 1, r.width, r.height - 2, arcSize, arcSize);
|
||||
g.setColor(myTextArea.isEnabled() ? Gray._100 : Gray._83);
|
||||
g.setColor(myTextArea.isEnabled() ? Gray._196 : Gray._83);
|
||||
|
||||
if (hasFocus) {
|
||||
DarculaUIUtil.paintSearchFocusRing(g, r, arcSize + 6);
|
||||
if (SystemInfo.isMac && (UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderAquaLookAndFeel())) {
|
||||
MacIntelliJTextFieldUI.paintAquaSearchFocusRing(g, r, myTextArea);
|
||||
}
|
||||
else {
|
||||
g.drawRoundRect(r.x, r.y, r.width, r.height - 1, arcSize, arcSize);
|
||||
JBInsets.removeFrom(r, new Insets(3, 3, 3, 3));
|
||||
if (hasFocus) {
|
||||
DarculaUIUtil.paintSearchFocusRing(g, r, myTextArea, arcSize+6);
|
||||
}
|
||||
else {
|
||||
g.drawRoundRect(r.x, r.y, r.width, r.height, arcSize, arcSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -150,7 +217,7 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList
|
||||
public ShowHistoryAction(boolean search) {
|
||||
super((search ? "Search" : "Replace") + " History",
|
||||
(search ? "Search" : "Replace") + " history",
|
||||
IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class, true));
|
||||
MacIntelliJIconCache.getIcon("searchFieldWithHistory"));
|
||||
|
||||
myShowSearchHistory = search;
|
||||
|
||||
@@ -166,7 +233,47 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList
|
||||
: findInProjectSettings.getRecentReplaceStrings();
|
||||
String title = "Recent " + (myShowSearchHistory ? "Searches" : "Replaces");
|
||||
JBList historyList = new JBList((Object[])ArrayUtil.reverseArray(recent));
|
||||
Utils.showCompletionPopup(myTextArea, historyList, title, myTextArea, null);
|
||||
Utils.showCompletionPopup(SearchTextArea.this, historyList, title, myTextArea, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static ActionButton createButton(AnAction action) {
|
||||
Presentation presentation = action.getTemplatePresentation();
|
||||
Icon icon = presentation.getIcon();
|
||||
Dimension d = new Dimension(JBUI.scale(16), JBUI.scale(16));
|
||||
if (icon != null) {
|
||||
d = new Dimension(JBUI.scale(icon.getIconWidth()), JBUI.scale(icon.getIconHeight()));
|
||||
}
|
||||
ActionButton button = new ActionButton(action, presentation, ActionPlaces.UNKNOWN, d) {
|
||||
@Override
|
||||
protected DataContext getDataContext() {
|
||||
return DataManager.getInstance().getDataContext(this);
|
||||
}
|
||||
};
|
||||
button.setLook(new InplaceActionButtonLook());
|
||||
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
return button;
|
||||
}
|
||||
|
||||
private class ClearAction extends DumbAwareAction {
|
||||
public ClearAction() {
|
||||
super(null, null, AllIcons.Actions.Clear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myTextArea.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
private class NewLineAction extends DumbAwareAction {
|
||||
public NewLineAction() {
|
||||
super(null, "New line (" + KeymapUtil.getKeystrokeText(SearchReplaceComponent.NEW_LINE_KEYSTROKE) + ")", AllIcons.Actions.NewLine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
new DefaultEditorKit.InsertBreakAction().actionPerformed(new ActionEvent(myTextArea, 0, "action"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.ui.JBMenuItem;
|
||||
import com.intellij.openapi.ui.JBPopupMenu;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.components.JBList;
|
||||
@@ -75,6 +76,15 @@ public class SearchTextField extends JPanel {
|
||||
super.processKeyEvent(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processMouseEvent(MouseEvent e) {
|
||||
TextUI ui = getUI();
|
||||
//noinspection unchecked
|
||||
if (ui instanceof Condition && ((Condition)ui).value(e)) return;
|
||||
|
||||
super.processMouseEvent(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(final Color bg) {
|
||||
super.setBackground(bg);
|
||||
|
||||
@@ -47,10 +47,11 @@ public class DarculaUIUtil {
|
||||
return new JBColor(new Color(35, 121, 212), new Color(96, 175, 255));
|
||||
}
|
||||
|
||||
public static void paintSearchFocusRing(Graphics2D g, Rectangle bounds) {
|
||||
paintSearchFocusRing(g, bounds, -1);
|
||||
public static void paintSearchFocusRing(Graphics2D g, Rectangle bounds, Component component) {
|
||||
paintSearchFocusRing(g, bounds, component, -1);
|
||||
}
|
||||
public static void paintSearchFocusRing(Graphics2D g, Rectangle bounds, int maxArcSize) {
|
||||
|
||||
public static void paintSearchFocusRing(Graphics2D g, Rectangle bounds, Component component, int maxArcSize) {
|
||||
int correction = UIUtil.isUnderAquaLookAndFeel() ? 30 : UIUtil.isUnderDarcula() ? 50 : 0;
|
||||
final Color[] colors = new Color[]{
|
||||
ColorUtil.toAlpha(getGlow(), 180 - correction),
|
||||
@@ -73,6 +74,9 @@ public class DarculaUIUtil {
|
||||
if (arcSize %2 == 1) arcSize--;
|
||||
|
||||
|
||||
g.setColor(component.getBackground());
|
||||
g.fillRoundRect(r.x + 2, r.y + 2, r.width - 5, r.height - 5, arcSize - 4, arcSize - 4);
|
||||
|
||||
g.setColor(colors[0]);
|
||||
g.drawRoundRect(r.x + 2, r.y + 2, r.width - 5, r.height - 5, arcSize-4, arcSize-4);
|
||||
|
||||
|
||||
+4
-10
@@ -18,18 +18,17 @@ package com.intellij.ide.ui.laf.darcula.ui;
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
import com.intellij.openapi.ui.GraphicsConfig;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.ui.paint.RectanglePainter;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
@@ -55,14 +54,9 @@ public class DarculaTextFieldUI extends TextFieldWithPopupHandlerUI {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasText() {
|
||||
JTextComponent component = getComponent();
|
||||
return (component != null) && !StringUtil.isEmpty(component.getText());
|
||||
}
|
||||
|
||||
public SearchAction getActionUnder(MouseEvent e) {
|
||||
public SearchAction getActionUnder(@NotNull Point p) {
|
||||
int off = JBUI.scale(8);
|
||||
Point point = new Point(e.getX() - off, e.getY() - off);
|
||||
Point point = new Point(p.x - off, p.y - off);
|
||||
return point.distance(getSearchIconCoord()) <= off
|
||||
? SearchAction.POPUP
|
||||
: hasText() && point.distance(getClearIconCoord()) <= off
|
||||
@@ -140,7 +134,7 @@ public class DarculaTextFieldUI extends TextFieldWithPopupHandlerUI {
|
||||
else if (c.hasFocus()) {
|
||||
g.setColor(c.getBackground());
|
||||
RectanglePainter.FILL.paint(g, r.x, r.y, r.width, r.height, radius);
|
||||
DarculaUIUtil.paintSearchFocusRing(g, r);
|
||||
DarculaUIUtil.paintSearchFocusRing(g, r, c);
|
||||
}
|
||||
else {
|
||||
RectanglePainter.paint(g, r.x, r.y, r.width, r.height, radius, c.getBackground(), c.isEnabled() ? Gray._100 : Gray._83);
|
||||
|
||||
+117
-48
@@ -16,6 +16,11 @@
|
||||
package com.intellij.ide.ui.laf.darcula.ui;
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaUIUtil;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.basic.BasicTextFieldUI;
|
||||
@@ -28,66 +33,41 @@ import java.awt.event.*;
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI {
|
||||
public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI implements Condition {
|
||||
protected final JTextField myTextField;
|
||||
private MyMouseMotionAdapter myMyMouseMotionAdapter;
|
||||
private MyMouseAdapter myMouseAdapter;
|
||||
private FocusAdapter myFocusAdapter;
|
||||
|
||||
public TextFieldWithPopupHandlerUI(JTextField textField) {
|
||||
myTextField = textField;
|
||||
installListeners();
|
||||
}
|
||||
|
||||
protected abstract SearchAction getActionUnder(MouseEvent e);
|
||||
protected boolean hasText() {
|
||||
JTextComponent component = getComponent();
|
||||
return (component != null) && !StringUtil.isEmpty(component.getText());
|
||||
}
|
||||
|
||||
protected abstract SearchAction getActionUnder(@NotNull Point p);
|
||||
|
||||
protected abstract void showSearchPopup();
|
||||
|
||||
protected void installListeners() {
|
||||
final TextFieldWithPopupHandlerUI ui = this;
|
||||
myTextField.addFocusListener(new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
myTextField.repaint();
|
||||
}
|
||||
myFocusAdapter = new MyFocusAdapter();
|
||||
myTextField.addFocusListener(myFocusAdapter);
|
||||
myMyMouseMotionAdapter = new MyMouseMotionAdapter(ui);
|
||||
myTextField.addMouseMotionListener(myMyMouseMotionAdapter);
|
||||
myMouseAdapter = new MyMouseAdapter(ui);
|
||||
myTextField.addMouseListener(myMouseAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
myTextField.repaint();
|
||||
}
|
||||
});
|
||||
myTextField.addMouseMotionListener(new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (ui.getComponent() != null && isSearchField(myTextField)) {
|
||||
if (ui.getActionUnder(e) != null) {
|
||||
myTextField.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
} else {
|
||||
myTextField.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
myTextField.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (isSearchField(myTextField)) {
|
||||
final SearchAction action = ui.getActionUnder(e);
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case POPUP:
|
||||
ui.showSearchPopup();
|
||||
break;
|
||||
case CLEAR:
|
||||
Object listener = myTextField.getClientProperty("JTextField.Search.CancelAction");
|
||||
if (listener instanceof ActionListener) {
|
||||
((ActionListener)listener).actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "action"));
|
||||
}
|
||||
myTextField.setText("");
|
||||
break;
|
||||
}
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
myTextField.removeFocusListener(myFocusAdapter);
|
||||
myTextField.removeMouseMotionListener(myMyMouseMotionAdapter);
|
||||
myTextField.removeMouseListener(myMouseAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,6 +77,20 @@ public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI {
|
||||
return position != -1 ? position : super.getNextVisualPositionFrom(t, pos, b, direction, biasRet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean value(Object o) {
|
||||
if (o instanceof MouseEvent) {
|
||||
MouseEvent me = (MouseEvent)o;
|
||||
if (getActionUnder(me.getPoint()) != null) {
|
||||
if (me.getID() == MouseEvent.MOUSE_CLICKED) {
|
||||
//noinspection SSBasedInspection
|
||||
SwingUtilities.invokeLater(() -> myMouseAdapter.mouseClicked(me));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSearchField(Component c) {
|
||||
return c instanceof JTextField && "search".equals(((JTextField)c).getClientProperty("JTextField.variant"));
|
||||
@@ -106,7 +100,82 @@ public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI {
|
||||
return isSearchField(c) && ((JTextField)c).getClientProperty("JTextField.Search.FindPopup") instanceof JPopupMenu;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AbstractAction getNewLineAction(Component c) {
|
||||
if ( !isSearchField(c) || !Registry.is("ide.find.show.add.newline.hint")) return null;
|
||||
Object action = ((JTextField)c).getClientProperty("JTextField.Search.NewLineAction");
|
||||
return action instanceof AbstractAction ? (AbstractAction)action : null;
|
||||
}
|
||||
|
||||
public enum SearchAction {
|
||||
POPUP, CLEAR
|
||||
POPUP, CLEAR, NEWLINE
|
||||
}
|
||||
|
||||
private class MyMouseMotionAdapter extends MouseMotionAdapter {
|
||||
private final TextFieldWithPopupHandlerUI myUi;
|
||||
|
||||
public MyMouseMotionAdapter(TextFieldWithPopupHandlerUI ui) {myUi = ui;}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (myUi.getComponent() != null && isSearchField(myTextField)) {
|
||||
SearchAction action = myUi.getActionUnder(e.getPoint());
|
||||
if (action == SearchAction.POPUP && !isSearchFieldWithHistoryPopup(myTextField)) {
|
||||
action = null;
|
||||
}
|
||||
if (action != null) {
|
||||
myTextField.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
} else {
|
||||
myTextField.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyMouseAdapter extends MouseAdapter {
|
||||
private final TextFieldWithPopupHandlerUI myUi;
|
||||
|
||||
public MyMouseAdapter(TextFieldWithPopupHandlerUI ui) {myUi = ui;}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (isSearchField(myTextField)) {
|
||||
final SearchAction action = myUi.getActionUnder(e.getPoint());
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case POPUP:
|
||||
myUi.showSearchPopup();
|
||||
break;
|
||||
case CLEAR:
|
||||
Object listener = myTextField.getClientProperty("JTextField.Search.CancelAction");
|
||||
if (listener instanceof ActionListener) {
|
||||
((ActionListener)listener).actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "action"));
|
||||
}
|
||||
myTextField.setText("");
|
||||
break;
|
||||
case NEWLINE: {
|
||||
AbstractAction newLineAction = getNewLineAction(myTextField);
|
||||
if (newLineAction != null) {
|
||||
newLineAction.actionPerformed(new ActionEvent(myTextField, ActionEvent.ACTION_PERFORMED, "action"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyFocusAdapter extends FocusAdapter {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
myTextField.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
myTextField.repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+104
-30
@@ -15,8 +15,12 @@
|
||||
*/
|
||||
package com.intellij.ide.ui.laf.intellij;
|
||||
|
||||
import com.intellij.ide.ui.laf.IntelliJLaf;
|
||||
import com.intellij.ide.ui.laf.darcula.ui.TextFieldWithPopupHandlerUI;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.util.ui.GraphicsUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -24,7 +28,8 @@ import javax.swing.*;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
@@ -49,33 +54,56 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasText() {
|
||||
JTextComponent component = getComponent();
|
||||
return (component != null) && !StringUtil.isEmpty(component.getText());
|
||||
@Override
|
||||
public String getToolTipText(JTextComponent t, Point pt) {
|
||||
if (getActionUnder(pt) == SearchAction.NEWLINE) {
|
||||
AbstractAction action = getNewLineAction(t);
|
||||
if (action != null) return (String)action.getValue(Action.SHORT_DESCRIPTION);
|
||||
}
|
||||
return super.getToolTipText(t, pt);
|
||||
}
|
||||
|
||||
public SearchAction getActionUnder(MouseEvent e) {
|
||||
public SearchAction getActionUnder(@NotNull Point p) {
|
||||
int off = JBUI.scale(8);
|
||||
Point point = new Point(e.getX() - off, e.getY() - off);
|
||||
return point.distance(getSearchIconCoord()) <= off
|
||||
? SearchAction.POPUP
|
||||
: hasText() && point.distance(getClearIconCoord()) <= off
|
||||
? SearchAction.CLEAR
|
||||
: null;
|
||||
Point point = new Point(p.x - off, p.y - off);
|
||||
if (point.distance(getSearchIconCoord()) <= off) {
|
||||
return SearchAction.POPUP;
|
||||
}
|
||||
if (hasText() && point.distance(getClearIconCoord()) <= off) {
|
||||
return SearchAction.CLEAR;
|
||||
}
|
||||
if (getNewLineAction(myTextField) != null && point.distance(getAddNewLineIconCoord()) <= off) {
|
||||
return SearchAction.NEWLINE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Rectangle getDrawingRect() {
|
||||
return new Rectangle(0, (myTextField.getHeight() - 26) / 2, myTextField.getWidth(), myTextField.getHeight());
|
||||
}
|
||||
|
||||
Icon getSearchIcon(Component c) {
|
||||
return MacIntelliJIconCache.getIcon(isSearchFieldWithHistoryPopup(c) ? "searchFieldWithHistory" : "searchFieldLabel");
|
||||
}
|
||||
|
||||
protected Point getSearchIconCoord() {
|
||||
final Rectangle r = getDrawingRect();
|
||||
return new Point(r.x + JBUI.scale(3), r.y + (r.height - JBUI.scale(16)) / 2 + JBUI.scale(1));
|
||||
Icon icon = getSearchIcon(myTextField);
|
||||
return new Point(r.x + (hasText() || myTextField.hasFocus() || isSearchFieldWithHistoryPopup(myTextField)
|
||||
? JBUI.scale(8)
|
||||
: (r.width - icon.getIconWidth()) / 2)
|
||||
, r.y + (r.height - icon.getIconHeight()) / 2 + JBUI.scale(1));
|
||||
}
|
||||
|
||||
protected Point getClearIconCoord() {
|
||||
final Rectangle r = getDrawingRect();
|
||||
return new Point(r.x + r.width - JBUI.scale(16) - JBUI.scale(2), r.y + (r.height - JBUI.scale(16)) / 2);
|
||||
return new Point(r.x + r.width - JBUI.scale(16) - JBUI.scale(6), r.y + (r.height - JBUI.scale(16)) / 2);
|
||||
}
|
||||
|
||||
protected Point getAddNewLineIconCoord() {
|
||||
Point point = getClearIconCoord();
|
||||
if (!StringUtil.isEmpty(myTextField.getText())) point.x -= JBUI.scale(16) + JBUI.scale(8);
|
||||
return point;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,11 +119,13 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI {
|
||||
|
||||
if (isSearchField(c)) {
|
||||
paintSearchField(g, c, r);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (c.getBorder() instanceof MacIntelliJTextBorder) {
|
||||
g.setColor(c.getBackground());
|
||||
g.fillRect(3, 3, c.getWidth() - 6, c.getHeight() - 6);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
super.paintBackground(g);
|
||||
}
|
||||
}
|
||||
@@ -122,39 +152,52 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI {
|
||||
x += left.getIconWidth();
|
||||
while (x < stop) {
|
||||
middle.paintIcon(c, gg, x, r.y);
|
||||
x+=middle.getIconWidth();
|
||||
x += middle.getIconWidth();
|
||||
}
|
||||
gg.dispose();
|
||||
right.paintIcon(c, g, stop, r.y);
|
||||
|
||||
boolean withHistoryPopup = isSearchFieldWithHistoryPopup(c);
|
||||
Icon label = MacIntelliJIconCache.getIcon(withHistoryPopup ? "searchFieldWithHistory" : "searchFieldLabel");
|
||||
if (StringUtil.isEmpty(c.getText()) && !c.hasFocus() && !withHistoryPopup) {
|
||||
label.paintIcon(c, g, r.x + (r.width - label.getIconWidth())/ 2, r.y);
|
||||
} else {
|
||||
Icon label = getSearchIcon(c);
|
||||
boolean isEmpty = !hasText();
|
||||
Point point = getSearchIconCoord();
|
||||
if (isEmpty && !c.hasFocus() && !withHistoryPopup) {
|
||||
label.paintIcon(c, g, point.x, point.y);
|
||||
}
|
||||
else {
|
||||
gg = g.create(0, 0, c.getWidth(), c.getHeight());
|
||||
int offset = withHistoryPopup ? 5 : 8;
|
||||
gg.setClip(r.x + offset, r.y, StringUtil.isEmpty(c.getText()) ? label.getIconWidth() : 16, label.getIconHeight());
|
||||
label.paintIcon(c, gg, r.x + offset, r.y);
|
||||
gg.setClip(point.x, point.y, isEmpty ? label.getIconWidth() : 16, label.getIconHeight());
|
||||
label.paintIcon(c, gg, point.x, point.y);
|
||||
}
|
||||
|
||||
if (!StringUtil.isEmpty(c.getText())) {
|
||||
Icon clear = MacIntelliJIconCache.getIcon("searchFieldClear");
|
||||
clear.paintIcon(c, g, r.x + r.width - clear.getIconWidth() - 6, r.y);
|
||||
Icon clearIcon = MacIntelliJIconCache.getIcon("searchFieldClear");
|
||||
if (!isEmpty) {
|
||||
clearIcon.paintIcon(c, g, getClearIconCoord().x, r.y);
|
||||
}
|
||||
AbstractAction newLineAction = getNewLineAction(c);
|
||||
if (newLineAction != null) {
|
||||
Icon newLineIcon = (Icon)newLineAction.getValue(Action.SMALL_ICON);
|
||||
if (newLineIcon != null) {
|
||||
newLineIcon.paintIcon(c, g, getAddNewLineIconCoord().x, r.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Rectangle getVisibleEditorRect() {
|
||||
Rectangle rect = super.getVisibleEditorRect();
|
||||
if (rect != null) {
|
||||
if (isSearchField(myTextField)) {
|
||||
rect.width -= 36;
|
||||
rect.x += 19;
|
||||
int extraOffset = isSearchFieldWithHistoryPopup(myTextField) ? 3 : 0;
|
||||
rect.width -= 36 + extraOffset;
|
||||
if (getNewLineAction(myTextField) != null) rect.width -= 24;
|
||||
rect.x += 19 + extraOffset;
|
||||
rect.y += 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
rect.x += 2;
|
||||
rect.width -=4;
|
||||
rect.width -= 4;
|
||||
}
|
||||
}
|
||||
return rect;
|
||||
@@ -165,4 +208,35 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI {
|
||||
paintBackground(g);
|
||||
super.paintSafely(g);
|
||||
}
|
||||
|
||||
public static void paintAquaSearchFocusRing(Graphics2D g, Rectangle r, Component c) {
|
||||
g = (Graphics2D)g.create(0, 0, r.width, r.height);
|
||||
GraphicsUtil.setupAAPainting(g);
|
||||
g.setColor(c.getBackground());
|
||||
RoundRectangle2D.Double border = getShape(r, 4, true);
|
||||
g.fill(border);
|
||||
|
||||
g.setColor(Gray._192);
|
||||
g.setStroke(new BasicStroke(.5f));
|
||||
g.draw(getShape(r, 4, false));
|
||||
|
||||
if (true || c.hasFocus()) {
|
||||
Color graphiteColor = new Color(0x6f6f72);
|
||||
Color blueColor = ColorUtil.brighter(new Color(0x006de2), 3);
|
||||
g.setColor(ColorUtil.withAlpha(IntelliJLaf.isGraphite() ? graphiteColor : blueColor, .3));
|
||||
Area area = new Area(getShape(r, 7, false));
|
||||
area.subtract(new Area(getShape(r, 3.5, true)));
|
||||
g.fill(area);
|
||||
}
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
private static RoundRectangle2D.Double getShape(Rectangle r, double radius, boolean inner) {
|
||||
double max_radius = 7;
|
||||
radius = Math.min(max_radius, Math.max(0, radius));
|
||||
double inset = max_radius - radius;
|
||||
double indent = inner ? 0.5 : 0;
|
||||
return new RoundRectangle2D.Double(r.x + inset + indent, r.y + inset + indent, r.width - 2 * inset - indent,
|
||||
r.height - 2 * inset - indent, 2 * radius, 2 * radius);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,6 +732,8 @@ removable.welcome.screen.projects.description=Allows removing recent projects fr
|
||||
ide.find.show.preview=true
|
||||
ide.find.as.popup=false
|
||||
ide.find.as.popup.description=Show new 'lightweight' popup instead of modal dialog (action 'Find in Path')
|
||||
ide.find.show.add.newline.hint=false
|
||||
ide.find.show.add.newline.hint.description=Enables icon with 'Enter' symbol inside a search field to help user with multiline search
|
||||
ide.remove.help.button.from.dialogs=false
|
||||
ide.remove.help.button.from.dialogs.description=Removes help button from dialogs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user