diff --git a/src/main/java/com/devoxx/genie/ui/component/GlowingBorder.java b/src/main/java/com/devoxx/genie/ui/component/GlowingBorder.java new file mode 100644 index 00000000..15fde505 --- /dev/null +++ b/src/main/java/com/devoxx/genie/ui/component/GlowingBorder.java @@ -0,0 +1,49 @@ +package com.devoxx.genie.ui.component; + +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; + +import javax.swing.border.AbstractBorder; +import java.awt.*; +import java.awt.geom.Area; +import java.awt.geom.RoundRectangle2D; + +public class GlowingBorder extends AbstractBorder { + private final Color glowColor; + private final int glowWidth = 4; + + @Getter + @Setter + private float alpha = 0.5f; + + public GlowingBorder(Color glowColor) { + this.glowColor = glowColor; + } + + @Override + public void paintBorder(Component c, @NotNull Graphics g, int x, int y, int width, int height) { + Graphics2D g2 = (Graphics2D) g.create(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + int arcWidth = 15; + int arcHeight = 15; + RoundRectangle2D.Float outer = new RoundRectangle2D.Float(x, y, width - 1, height - 1, arcWidth, arcHeight); + RoundRectangle2D.Float inner = new RoundRectangle2D.Float(x + glowWidth, y + glowWidth, width - glowWidth * 2 - 1, height - glowWidth * 2 - 1, arcWidth, arcHeight); + + Area area = new Area(outer); + area.subtract(new Area(inner)); + + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); + g2.setColor(glowColor); + g2.fill(area); + + g2.dispose(); + } + + @Override + public Insets getBorderInsets(Component c) { + return new Insets(glowWidth, glowWidth, glowWidth, glowWidth); + } + +} diff --git a/src/main/java/com/devoxx/genie/ui/component/PromptInputArea.java b/src/main/java/com/devoxx/genie/ui/component/PromptInputArea.java index 4f7148d1..0abcb125 100644 --- a/src/main/java/com/devoxx/genie/ui/component/PromptInputArea.java +++ b/src/main/java/com/devoxx/genie/ui/component/PromptInputArea.java @@ -1,34 +1,70 @@ package com.devoxx.genie.ui.component; import com.devoxx.genie.ui.listener.PromptInputFocusListener; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ResourceBundle; public class PromptInputArea extends JPanel { private final CommandAutoCompleteTextField inputField; + private final GlowingBorder glowingBorder; + private final Timer glowTimer; + private boolean isGlowing = false; - public PromptInputArea(ResourceBundle resourceBundle) { + public PromptInputArea(@NotNull ResourceBundle resourceBundle) { super(new BorderLayout()); inputField = new CommandAutoCompleteTextField(); - inputField.setRows(3); inputField.setLineWrap(true); inputField.setWrapStyleWord(true); - inputField.setAutoscrolls(false); inputField.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - inputField.setMinimumSize(new Dimension(0, 75)); inputField.addFocusListener(new PromptInputFocusListener(inputField)); inputField.setPlaceholder(resourceBundle.getString("prompt.placeholder")); - JScrollPane scrollPane = new JScrollPane(inputField); - scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - scrollPane.setBorder(null); + glowingBorder = new GlowingBorder(new Color(0, 120, 215)); // You can change this color + setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); // To accommodate the glowing border - add(scrollPane, BorderLayout.CENTER); - setMaximumSize(new Dimension(Integer.MAX_VALUE, getPreferredSize().height)); + add(inputField, BorderLayout.CENTER); + + glowTimer = new Timer(50, new ActionListener() { + private float direction = 0.05f; + @Override + public void actionPerformed(ActionEvent e) { + float alpha = glowingBorder.getAlpha(); + alpha += direction; + if (alpha > 1.0f) { + alpha = 1.0f; + direction = -0.05f; + } else if (alpha < 0.3f) { + alpha = 0.3f; + direction = 0.05f; + } + glowingBorder.setAlpha(alpha); + repaint(); + } + }); + } + + public void startGlowing() { + if (!isGlowing) { + isGlowing = true; + setBorder(glowingBorder); + glowTimer.start(); + } + } + + public void stopGlowing() { + if (isGlowing) { + isGlowing = false; + glowTimer.stop(); + setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + repaint(); + } } public String getText() { @@ -50,8 +86,4 @@ public void setEnabled(boolean enabled) { public boolean requestFocusInWindow() { return inputField.requestFocusInWindow(); } - - public void setPlaceholder(String placeholder) { - inputField.setPlaceholder(placeholder); - } } diff --git a/src/main/java/com/devoxx/genie/ui/panel/ActionButtonsPanel.java b/src/main/java/com/devoxx/genie/ui/panel/ActionButtonsPanel.java index 15ff5927..8371d824 100644 --- a/src/main/java/com/devoxx/genie/ui/panel/ActionButtonsPanel.java +++ b/src/main/java/com/devoxx/genie/ui/panel/ActionButtonsPanel.java @@ -59,7 +59,6 @@ public class ActionButtonsPanel extends JPanel implements SettingsChangeListener private final ComboBox llmProvidersComboBox; private final ComboBox modelNameComboBox; private final TokenUsageBar tokenUsageBar = new TokenUsageBar(); - private final JProgressBar progressBar = new JProgressBar(); private int tokenCount; private final DevoxxGenieToolWindowContent devoxxGenieToolWindowContent; @@ -123,15 +122,11 @@ public void setupUI() { add(addFileBtn, BorderLayout.EAST); add(addProjectBtn, BorderLayout.SOUTH); - progressBar.setVisible(false); - progressBar.setIndeterminate(true); - tokenUsageBar.setVisible(false); tokenUsageBar.setPreferredSize(new Dimension(Integer.MAX_VALUE, 3)); JPanel progressPanel = new JPanel(new BorderLayout()); progressPanel.add(tokenUsageBar, BorderLayout.CENTER); - progressPanel.add(progressBar, BorderLayout.SOUTH); add(progressPanel, BorderLayout.NORTH); } @@ -181,8 +176,6 @@ private void selectFilesForPromptContext(ActionEvent e) { * Submit the user prompt. */ private void onSubmitPrompt(ActionEvent actionEvent) { - progressBar.setVisible(true); - if (isPromptRunning) { stopPromptExecution(); return; @@ -213,6 +206,7 @@ private void executePrompt() { */ private void startPromptExecution() { isPromptRunning = true; + promptInputArea.startGlowing(); chatPromptExecutor.executePrompt(currentChatMessageContext, promptOutputPanel, this::enableButtons); } @@ -274,6 +268,7 @@ private boolean isProjectContextSupportedProvider() { private void disableUIForPromptExecution() { disableSubmitBtn(); disableButtons(); + promptInputArea.startGlowing(); } /** @@ -313,9 +308,9 @@ public void enableButtons() { SwingUtilities.invokeLater(() -> { submitBtn.setIcon(SubmitIcon); submitBtn.setToolTipText(SUBMIT_THE_PROMPT); - progressBar.setVisible(false); promptInputArea.setEnabled(true); isPromptRunning = false; + promptInputArea.stopGlowing(); }); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a2cfd8b3..d3ef79dc 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,2 @@ -#Tue Jul 02 13:43:13 CEST 2024 -version=0.2.0 +#Tue Jul 02 18:49:47 CEST 2024 +version=0.2.1