reloadAndGetBackgrounds() {
- reloadBackgrounds();
- return backgrounds;
- }
-
- /**
- * Revalidates the index that the current background is at after
- * refreshing due to a possible background list change.
- */
- private void revalidateBackgroundIndex() {
- if (consoleCyderFrame == null) {
- backgroundIndex = 0;
- return;
- }
-
- JLabel contentLabel = getConsoleCyderFrameContentPane();
- if (contentLabel == null) {
- backgroundIndex = 0;
- return;
- }
-
- String filename = contentLabel.getToolTipText();
- if (StringUtil.isNullOrEmpty(filename)) {
- backgroundIndex = 0;
- return;
- }
-
- for (int i = 0 ; i < backgrounds.size() ; i++) {
- if (FileUtil.getFilename(backgrounds.get(i).getReferenceFile()).equals(filename)) {
- backgroundIndex = i;
- return;
- }
- }
-
- backgroundIndex = 0;
- }
-
- /**
- * Sets the background to the provided file in the user's backgrounds directory provided it exists.
- *
- * @param backgroundFile the background file to set the console to
- */
- public void setBackgroundFile(File backgroundFile) {
- Preconditions.checkNotNull(backgroundFile);
- Preconditions.checkArgument(backgroundFile.exists());
-
- setBackgroundFile(backgroundFile, false);
- }
-
- /**
- * Sets the background to the provided file in the user's backgrounds directory provided it exists.
- *
- * @param backgroundFile the background file to set the console to
- * @param maintainSizeAndCenter whether to maintain the current console frame size and center
- */
- public void setBackgroundFile(File backgroundFile, boolean maintainSizeAndCenter) {
- Preconditions.checkNotNull(backgroundFile);
- Preconditions.checkArgument(backgroundFile.exists());
-
- reloadBackgrounds();
-
- for (int i = 0 ; i < backgrounds.size() ; i++) {
- if (backgrounds.get(i).getReferenceFile().getAbsolutePath()
- .equals(backgroundFile.getAbsolutePath())) {
- setBackgroundIndex(i, maintainSizeAndCenter);
- return;
- }
- }
-
- throw new IllegalArgumentException("Provided file not found in user's backgrounds directory: "
- + backgroundFile.getAbsolutePath());
- }
-
- /**
- * Simply sets the background to the provided icon without having a reference file.
- * Please ensure the icon size is the same as the current background's.
- *
- * @param icon the icon to set to the background of the console
- */
- public void setBackground(ImageIcon icon) {
- Preconditions.checkNotNull(icon);
- Preconditions.checkArgument(icon.getIconWidth() == consoleCyderFrame.getWidth());
- Preconditions.checkArgument(icon.getIconHeight() == consoleCyderFrame.getHeight());
-
- consoleCyderFrame.setBackground(icon);
- }
-
- /**
- * Sets the background index to the provided index
- * if valid and switches to that background.
- *
- * @param index the index to switch the console background to
- */
- @SuppressWarnings("unused")
- private void setBackgroundIndex(int index) {
- setBackgroundIndex(index, false);
- }
-
- /**
- * Sets the background index to the provided index
- * if valid and switches to that background.
- *
- * @param index the index to switch the console background to
- * @param maintainSizeAndCenter whether to maintain the current console frame size and center
- */
- private void setBackgroundIndex(int index, boolean maintainSizeAndCenter) {
- reloadBackgrounds();
-
- if (index < 0 || index > backgrounds.size() - 1) return;
-
- Dimension originalSize = consoleCyderFrame.getSize();
- Point center = consoleCyderFrame.getCenterPointOnScreen();
-
- backgroundIndex = index;
-
- ImageIcon imageIcon = switch (consoleDir) {
- case LEFT -> new ImageIcon(ImageUtil.rotateImage(
- backgrounds.get(backgroundIndex).generateBufferedImage(), -AngleUtil.NINETY_DEGREES));
- case RIGHT -> new ImageIcon(ImageUtil.rotateImage(
- backgrounds.get(backgroundIndex).generateBufferedImage(), AngleUtil.NINETY_DEGREES));
- case TOP -> getCurrentBackground().generateImageIcon();
- case BOTTOM -> new ImageIcon(ImageUtil.rotateImage(
- backgrounds.get(backgroundIndex).generateBufferedImage(), AngleUtil.ONE_EIGHTY_DEGREES));
- };
-
- consoleCyderFrame.setBackground(imageIcon);
-
- if (maintainSizeAndCenter) {
- consoleCyderFrame.setSize(originalSize);
- consoleCyderFrame.setCenterPoint(center);
- } else {
- consoleCyderFrame.setSize(imageIcon.getIconWidth(), imageIcon.getIconHeight());
- consoleCyderFrame.setLocation((int) (center.getX() - (imageIcon.getIconWidth()) / 2),
- (int) (center.getY() - (imageIcon.getIconHeight()) / 2));
- }
-
- // Tooltip based on image name
- getConsoleCyderFrameContentPane().setToolTipText(
- FileUtil.getFilename(getCurrentBackground().getReferenceFile().getName()));
-
- revalidateInputAndOutputBounds();
- inputField.requestFocus();
- revalidateConsoleTaskbarMenu();
- }
-
- /**
- * Returns the current background.
- *
- * @return the current background
- */
- public ConsoleBackground getCurrentBackground() {
- return backgrounds.get(backgroundIndex);
- }
-
- /**
- * Whether the background switching is locked meaning an animation is currently underway.
- */
- private final AtomicBoolean backgroundSwitchingLocked = new AtomicBoolean(false);
-
- /**
- * The name of the thread which animates the background switch.
- */
- private static final String CONSOLE_BACKGROUND_SWITCHER_THREAD_NAME = "Console Background Switcher";
-
- /**
- * Switches backgrounds to the next background in the list via a sliding animation.
- * The Console will remain in fullscreen mode if in fullscreen mode as well as maintain
- * whatever size it was at before a background switch was requested.
- */
- @SuppressWarnings("UnnecessaryDefault")
- private void attemptToSwitchBackground() {
- if (backgroundSwitchingLocked.get()) return;
- if (backgrounds.size() == 1) {
- consoleCyderFrame.notify(onlyOneBackgroundNotificationBuilder);
- return;
- }
- backgroundSwitchingLocked.set(true);
-
- ImageIcon nextBackground = (backgroundIndex + 1 == backgrounds.size()
- ? backgrounds.get(0).generateImageIcon()
- : backgrounds.get(backgroundIndex + 1).generateImageIcon());
-
- backgroundIndex = backgroundIndex + 1 == backgrounds.size() ? 0 : backgroundIndex + 1;
-
- int width = nextBackground.getIconWidth();
- int height = nextBackground.getIconHeight();
-
- if (isFullscreen()) {
- width = (int) consoleCyderFrame.getMonitorBounds().getWidth();
- height = (int) consoleCyderFrame.getMonitorBounds().getHeight();
- nextBackground = ImageUtil.resizeImage(nextBackground, width, height);
- } else if (consoleDir == Direction.LEFT) {
- width = nextBackground.getIconHeight();
- height = nextBackground.getIconWidth();
- nextBackground = ImageUtil.rotateImage(nextBackground, -AngleUtil.NINETY_DEGREES);
- } else if (consoleDir == Direction.RIGHT) {
- width = nextBackground.getIconHeight();
- height = nextBackground.getIconWidth();
- nextBackground = ImageUtil.rotateImage(nextBackground, AngleUtil.NINETY_DEGREES);
- } else if (consoleDir == Direction.BOTTOM) {
- width = nextBackground.getIconWidth();
- height = nextBackground.getIconHeight();
- nextBackground = ImageUtil.rotateImage(nextBackground, AngleUtil.ONE_EIGHTY_DEGREES);
- }
-
- JLabel contentPane = getConsoleCyderFrameContentPane();
- contentPane.setToolTipText(FileUtil.getFilename(getCurrentBackground().getReferenceFile().getName()));
-
- ImageIcon nextBackFinal = nextBackground;
- ImageIcon oldBack = ImageUtil.resizeImage((ImageIcon) contentPane.getIcon(), width, height);
-
- Point originalCenter = consoleCyderFrame.getCenterPointOnScreen();
- consoleCyderFrame.setSize(width, height);
-
- // Bump frame into bounds if new size pushed part out of bounds
- UiUtil.requestFramePosition(new Point((int) originalCenter.getX() - width / 2,
- (int) originalCenter.getY() - height / 2), consoleCyderFrame);
-
- ImageIcon combinedIcon = switch (lastSlideDirection) {
- case LEFT -> ImageUtil.combineImages(oldBack, nextBackground, Direction.BOTTOM);
- case RIGHT -> ImageUtil.combineImages(oldBack, nextBackground, Direction.TOP);
- case TOP -> ImageUtil.combineImages(oldBack, nextBackground, Direction.LEFT);
- case BOTTOM -> ImageUtil.combineImages(oldBack, nextBackground, Direction.RIGHT);
- default -> throw new IllegalStateException("Invalid last slide direction: " + lastSlideDirection);
- };
-
- // Revalidate bounds for icon label and icon pane
- consoleCyderFrame.refreshBackground();
-
- // Determine this slide direction
- Direction nextSlideDirection;
- switch (lastSlideDirection) {
- case LEFT -> nextSlideDirection = Direction.TOP;
- case RIGHT -> nextSlideDirection = Direction.BOTTOM;
- case TOP -> nextSlideDirection = Direction.RIGHT;
- case BOTTOM -> nextSlideDirection = Direction.LEFT;
- default -> throw new IllegalStateException("Invalid last slide direction: " + lastSlideDirection);
- }
-
- // Set dimensions
- switch (nextSlideDirection) {
- case TOP -> contentPane.setBounds(CyderFrame.FRAME_RESIZING_LEN, CyderFrame.FRAME_RESIZING_LEN,
- combinedIcon.getIconWidth(), combinedIcon.getIconHeight());
- case BOTTOM -> contentPane.setBounds(CyderFrame.FRAME_RESIZING_LEN, -combinedIcon.getIconHeight() / 2,
- combinedIcon.getIconWidth(), combinedIcon.getIconHeight());
- case RIGHT -> contentPane.setBounds(-combinedIcon.getIconWidth() / 2, CyderFrame.FRAME_RESIZING_LEN,
- combinedIcon.getIconWidth(), combinedIcon.getIconHeight());
- case LEFT -> contentPane.setBounds(combinedIcon.getIconWidth() / 2, CyderFrame.FRAME_RESIZING_LEN,
- combinedIcon.getIconWidth(), combinedIcon.getIconHeight());
- }
-
- // set to combined icon
- contentPane.setIcon(combinedIcon);
-
- boolean wasDraggable = consoleCyderFrame.isDraggingEnabled();
- consoleCyderFrame.disableDragging();
-
- boolean outputAreaWasFocusable = outputArea.isFocusable();
- outputArea.setFocusable(false);
-
- Executors.newSingleThreadExecutor(new CyderThreadFactory(CONSOLE_BACKGROUND_SWITCHER_THREAD_NAME))
- .submit(() -> {
- int timeout =
- isFullscreen() ? fullscreenBackgroundAnimationTimeout : defaultBackgroundAnimationTimeout;
- int increment = isFullscreen() ? fullscreenBackgroundAnimationIncrement :
- defaultBackgroundAnimationIncrement;
-
- switch (nextSlideDirection) {
- case TOP -> {
- for (int i = 0 ; i >= -consoleCyderFrame.getHeight() ; i -= increment) {
- ThreadUtil.sleep(timeout);
- contentPane.setLocation(consoleCyderFrame.getContentPane().getX(), i);
- }
- lastSlideDirection = nextSlideDirection;
- }
- case BOTTOM -> {
- for (int i = -consoleCyderFrame.getHeight() ; i <= 0 ; i += increment) {
- ThreadUtil.sleep(timeout);
- contentPane.setLocation(consoleCyderFrame.getContentPane().getX(), i);
- }
- lastSlideDirection = nextSlideDirection;
- }
- case RIGHT -> {
- for (int i = -consoleCyderFrame.getWidth() ; i <= 0 ; i += increment) {
- ThreadUtil.sleep(timeout);
- contentPane.setLocation(i, consoleCyderFrame.getContentPane().getY());
- }
- lastSlideDirection = nextSlideDirection;
- }
- case LEFT -> {
- for (int i = 0 ; i >= -consoleCyderFrame.getWidth() ; i -= increment) {
- ThreadUtil.sleep(timeout);
- contentPane.setLocation(i, consoleCyderFrame.getContentPane().getY());
- }
- lastSlideDirection = nextSlideDirection;
- }
- }
-
- consoleCyderFrame.setBackground(nextBackFinal);
- contentPane.setIcon(nextBackFinal);
-
- consoleCyderFrame.refreshBackground();
- consoleCyderFrame.getContentPane().revalidate();
-
- refreshConsoleMaxSize();
-
- consoleCyderFrame.setDraggingEnabled(wasDraggable);
-
- revalidateMaintainFullscreenOrDirection();
-
- defaultFocusOwner.requestFocus();
-
- outputArea.setFocusable(outputAreaWasFocusable);
-
- backgroundSwitchingLocked.set(false);
- });
- }
-
- /**
- * Whether chams (chameleon mode) is currently active.
- */
- private final AtomicBoolean chamsActive = new AtomicBoolean();
-
- /**
- * Sets the console orientation and refreshes the frame.
- * This action exits fullscreen mode if active.
- *
- * @param consoleDirection the direction the background is to face
- */
- private void setConsoleDirection(Direction consoleDirection) {
- boolean maintainConsoleSize = consoleDirection != consoleDir;
- lastConsoleDir = consoleDir;
- consoleDir = consoleDirection;
-
- // If chams, reset to what background should be first
- if (chamsActive.get()) {
- revalidate(true, false, true);
- chamsActive.set(false);
- return;
- }
-
- UserDataManager.INSTANCE.setFullscreen(false);
- revalidate(true, false, maintainConsoleSize);
- revalidateConsoleMenuSize();
- saveScreenStat();
- }
-
- /**
- * Returns the current console direction.
- *
- * @return the current console direction
- */
- private Direction getConsoleDirection() {
- return consoleDir;
- }
-
- /**
- * Refreshes the console, bounds, orientation, and fullscreen mode.
- *
- * @param fullscreen whether to set the frame to fullscreen mode
- */
- public void setFullscreen(boolean fullscreen) {
- try {
- UserDataManager.INSTANCE.setFullscreen(fullscreen);
-
- if (fullscreen) {
- consoleDir = Direction.TOP;
- consoleCyderFrame.setShouldAnimateOpacity(false);
- revalidate(false, true);
- } else {
- consoleCyderFrame.setShouldAnimateOpacity(true);
- revalidate(true, false);
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
-
- @ForReadability
- private boolean isFullscreen() {
- return UserDataManager.INSTANCE.isFullscreen();
- }
-
- /**
- * Returns the input handler associated with the Console.
- *
- * @return the input handler associated with the Console
- */
- public BaseInputHandler getInputHandler() {
- return baseInputHandler;
- }
-
- // --------------------
- // Command history mods
- // --------------------
-
- /**
- * Wipes all command history and sets the command index back to 0.
- */
- public void clearCommandHistory() {
- commandList.clear();
- commandIndex = 0;
- }
-
- // ----------
- // Ui getters
- // ----------
-
- /**
- * Returns the JTextPane associated with the Console.
- *
- * @return the JTextPane associated with the Console
- */
- public JTextPane getOutputArea() {
- return outputArea;
- }
-
- /**
- * Returns the JScrollPane associated with the Console.
- *
- * @return the JScrollPane associated with the Console
- */
- public CyderScrollPane getOutputScroll() {
- return outputScroll;
- }
-
- /**
- * Returns the input JTextField associated with the Console.
- *
- * @return the input JTextField associated with the Console
- */
- public JTextField getInputField() {
- return inputField;
- }
-
- /**
- * Invokes the {@link #revalidate(boolean, boolean)} method, maintaining either full screen or direction,
- * not both. Maintaining fullscreen takes precedent over maintaining the console direction.
- */
- public void revalidateMaintainFullscreenOrDirection() {
- boolean fullscreen = isFullscreen();
- revalidate(!fullscreen, fullscreen);
- }
-
- /**
- * Revalidates the Console size, bounds, background, menu, clock, audio menu, draggable property, etc.
- * based on the current background. Note that maintainDirection trumps maintainFullscreen.
- *
- * @param maintainDirection whether to maintain the console direction
- * @param maintainFullscreen whether to maintain fullscreen mode
- */
- public void revalidate(boolean maintainDirection, boolean maintainFullscreen) {
- revalidate(maintainDirection, maintainFullscreen, false);
- }
-
- /**
- * Returns the current console background accounting for the console direction.
- *
- * @return the current console background accounting for the console direction
- */
- public ImageIcon getCurrentRotatedConsoleBackground() {
- return switch (consoleDir) {
- case TOP -> getCurrentBackground().generateImageIcon();
- case LEFT -> new ImageIcon(ImageUtil.getRotatedImage(
- getCurrentBackground().getReferenceFile().getAbsolutePath(), Direction.LEFT));
- case RIGHT -> new ImageIcon(ImageUtil.getRotatedImage(
- getCurrentBackground().getReferenceFile().getAbsolutePath(), Direction.RIGHT));
- case BOTTOM -> new ImageIcon(ImageUtil.getRotatedImage(
- getCurrentBackground().getReferenceFile().getAbsolutePath(), Direction.BOTTOM));
- };
- }
-
- /**
- * Revalidates the following console properties:
- *
- * Whether the frame should animate opacity on click events
- * Background
- * Background size
- * Ensuring the frame position is completely in bounds of the monitor
- * Input and output bounds
- * Console max size
- * Console menu
- * Whether dragging is enabled
- * Menu bounds, including the audio menu
- *
- *
- * Order of priority is as follows: maintainDirection, maintainFullscreen.
- * Neither of these affect maintainConsoleSize.
- *
- * @param maintainDirection whether to maintain the console direction
- * @param maintainFullscreen whether to maintain fullscreen mode
- * @param maintainConsoleSize whether to maintain the currently set size of the console
- */
- public void revalidate(boolean maintainDirection, boolean maintainFullscreen, boolean maintainConsoleSize) {
- Point originalCenter = consoleCyderFrame.getCenterPointOnScreen();
-
- ImageIcon background;
-
- if (maintainDirection) {
- background = getCurrentRotatedConsoleBackground();
-
- UserDataManager.INSTANCE.setFullscreen(false);
- consoleCyderFrame.setShouldAnimateOpacity(true);
- } else if (maintainFullscreen && UserDataManager.INSTANCE.isFullscreen()) {
- // Setup fullscreen on current monitor
- background = ImageUtil.resizeImage(getCurrentBackground().generateImageIcon(),
- (int) consoleCyderFrame.getMonitorBounds().getWidth(),
- (int) consoleCyderFrame.getMonitorBounds().getHeight());
- consoleCyderFrame.setShouldAnimateOpacity(false);
- } else {
- background = getCurrentBackground().generateImageIcon();
- }
-
- int width = consoleCyderFrame.getWidth();
- int height = consoleCyderFrame.getHeight();
-
- if (maintainConsoleSize) {
- switch (consoleDir) {
- case TOP, BOTTOM -> {
- if (Direction.isHorizontal(lastConsoleDir)) {
- background = ImageUtil.resizeImage(background, height, width);
- } else {
- background = ImageUtil.resizeImage(background, width, height);
- }
- }
- case LEFT, RIGHT -> {
- if (Direction.isHorizontal(lastConsoleDir)) {
- background = ImageUtil.resizeImage(background, width, height);
- } else {
- background = ImageUtil.resizeImage(background, height, width);
- }
- }
- }
- }
-
- int w = background.getIconWidth();
- int h = background.getIconHeight();
-
- consoleCyderFrame.setSize(w, h);
- consoleCyderFrame.setBackground(background);
-
- int topLeftX = (int) originalCenter.getX() - w / 2;
- int topLeftY = (int) originalCenter.getY() - h / 2;
- UiUtil.requestFramePosition(new Point(topLeftX, topLeftY), consoleCyderFrame);
-
- revalidateInputAndOutputBounds();
-
- refreshConsoleMaxSize();
-
- // This takes care of offset of input field and output area too
- revalidateConsoleTaskbarMenu();
-
- consoleCyderFrame.refreshBackground();
- consoleCyderFrame.setDraggingEnabled(!isFullscreen());
-
- revalidateConsoleTaskbarMenu();
- revalidateAudioMenuBounds();
- }
-
- /**
- * Returns the CyderFrame used for the Console.
- *
- * @return the CyderFrame used for the Console
- */
- public CyderFrame getConsoleCyderFrame() {
- return consoleCyderFrame;
- }
-
- // --------------------------------
- // menu generation and revalidation
- // --------------------------------
-
- /**
- * Sets the visibility of the audio controls button to true.
- */
- public void showAudioButton() {
- toggleAudioControls.setVisible(true);
- }
-
- /**
- * Revalidates the console menu bounds and places
- * it where it in the proper spot depending on if it is shown.
- * The taskbar icons are also regenerated and shown.
- */
- public void revalidateConsoleTaskbarMenu() {
- if (consoleClosed.get() || menuLabel == null) return;
-
- installMenuTaskbarIcons();
-
- // revalidate bounds if needed and change icon
- if (menuLabel.isVisible()) {
- menuLabel.setBounds(
- (int) consoleMenuShowingPoint.getX(),
- (int) consoleMenuShowingPoint.getY(),
- TASKBAR_MENU_WIDTH,
- calculateMenuHeight());
-
- int width = menuLabel.getWidth() - 2 * menuScrollHorizontalPadding;
- int height = menuLabel.getHeight() - 2 * menuScrollVerticalPadding;
- menuScroll.setBounds(menuScrollHorizontalPadding, menuScrollVerticalPadding, width, height);
- }
-
- revalidateInputAndOutputBounds();
- }
-
- /**
- * The name of the console audio menu minimizer thread.
- */
- private static final String CONSOLE_AUDIO_MENU_MINIMIZER_THREAD_NAME = "Console Audio Menu Minimizer";
-
- /**
- * The increment for audio menu animations.
- */
- private static final int audioMenuAnimationIncrement = 8;
-
- /**
- * The delay for audio menu animations.
- */
- private static final int audioMenuAnimationDelayMs = 10;
-
- /**
- * Smoothly animates out the console audio controls.
- */
- private void animateOutAudioControls() {
- CyderThreadRunner.submit(() -> {
- for (int i = audioControlsLabel.getY() ; i > -AUDIO_MENU_LABEL_HEIGHT ; i -= audioMenuAnimationIncrement) {
- audioControlsLabel.setLocation(consoleCyderFrame.getWidth()
- - audioControlsLabel.getWidth() - AUDIO_MENU_X_OFFSET, i);
- ThreadUtil.sleep(audioMenuAnimationDelayMs);
- }
- audioControlsLabel.setVisible(false);
- }, CONSOLE_AUDIO_MENU_MINIMIZER_THREAD_NAME);
- }
-
- /**
- * Smooth animates out and removes the audio controls button.
- */
- public void animateOutAndRemoveAudioControls() {
- CyderThreadRunner.submit(() -> {
- for (int i = audioControlsLabel.getY() ; i > -AUDIO_MENU_LABEL_HEIGHT ; i -= audioMenuAnimationIncrement) {
- audioControlsLabel.setLocation(consoleCyderFrame.getWidth()
- - audioControlsLabel.getWidth() - AUDIO_MENU_X_OFFSET, i);
- ThreadUtil.sleep(audioMenuAnimationDelayMs);
- }
- audioControlsLabel.setVisible(false);
- removeAudioControls();
- }, CONSOLE_AUDIO_MENU_MINIMIZER_THREAD_NAME);
- }
-
- /**
- * Smoothly animates in the audio controls.
- */
- private void animateInAudioControls() {
- CyderThreadRunner.submit(() -> {
- generateAudioMenu();
-
- int y = CyderDragLabel.DEFAULT_HEIGHT - AUDIO_MENU_LABEL_HEIGHT;
- audioControlsLabel.setLocation(calculateAudioMenuX(), y);
-
- audioControlsLabel.setVisible(true);
-
- for (int i = y ; i < CyderDragLabel.DEFAULT_HEIGHT - 2 ; i += audioMenuAnimationIncrement) {
- audioControlsLabel.setLocation(calculateAudioMenuX(), i);
- ThreadUtil.sleep(audioMenuAnimationDelayMs);
- }
-
- audioControlsLabel.setLocation(calculateAudioMenuX(), CyderDragLabel.DEFAULT_HEIGHT - 2);
- }, CONSOLE_AUDIO_MENU_MINIMIZER_THREAD_NAME);
- }
-
- /**
- * Revalidates the visibility audio menu and the play/pause button based on if audio is playing.
- */
- public void revalidateAudioMenuVisibility() {
- if (!AudioPlayer.isWidgetOpen() && !GeneralAudioPlayer.isGeneralAudioPlaying()) {
- if (audioControlsLabel.isVisible()) {
- animateOutAndRemoveAudioControls();
- } else {
- removeAudioControls();
- }
- } else {
- if (!audioControlsLabel.isVisible()) {
- audioControlsLabel.setLocation(audioControlsLabel.getX(), -AUDIO_MENU_LABEL_HEIGHT);
- toggleAudioControls.setVisible(true);
- }
-
- revalidateAudioMenuPlayPauseButton();
- }
- }
-
- /**
- * Revalidates the play pause audio label button icon.
- */
- @ForReadability
- private void revalidateAudioMenuPlayPauseButton() {
- boolean playing = GeneralAudioPlayer.generalOrAudioPlayerAudioPlaying();
- playPauseAudioLabel.setIcon(playing ? AudioIcons.pauseIcon : AudioIcons.playIcon);
- }
-
- /**
- * Hides the audio controls menu and toggle button.
- */
- private void removeAudioControls() {
- audioControlsLabel.setVisible(false);
- toggleAudioControls.setVisible(false);
- consoleCyderFrame.getTopDragLabel().refreshRightButtons();
- }
-
- /**
- * The number of audio menu buttons.
- */
- private static final int AUDIO_MENU_BUTTONS = 3;
-
- /**
- * The size of each audio menu button.
- */
- private static final int AUDIO_MENU_BUTTON_SIZE = 30;
-
- /**
- * The height of the audio menu.
- */
- private static final int AUDIO_MENU_LABEL_HEIGHT = 40;
-
- /**
- * The padding between buttons for the audio menu.
- */
- private static final int AUDIO_MENU_X_PADDING = 10;
-
- /**
- * The audio menu button y padding.
- */
- private static final int AUDIO_MENU_BUTTON_Y_PADDING = (AUDIO_MENU_LABEL_HEIGHT - AUDIO_MENU_BUTTON_SIZE) / 2;
-
- /**
- * The width of the audio menu.
- */
- private static final int AUDIO_MENU_LABEL_WIDTH = AUDIO_MENU_BUTTON_SIZE * AUDIO_MENU_BUTTONS
- + AUDIO_MENU_X_PADDING * (AUDIO_MENU_BUTTONS + 1);
-
- /**
- * The offset between the end of the audio menu label and the end of the console frame.
- */
- private static final int AUDIO_MENU_X_OFFSET = CyderFrame.BORDER_LEN + 1;
-
- /**
- * The tooltip for the previous audio menu button.
- */
- private static final String PREVIOUS = "Previous";
-
- /**
- * The tooltip for the play pause audio menu button.
- */
- private static final String PLAY_PAUSE = "Play/Pause";
-
- /**
- * The tooltip for the skip audio menu button.
- */
- private static final String SKIP = "Skip";
-
- /**
- * Returns the x value to place the audio menu at.
- *
- * @return the x value to place the audio menu at
- */
- private int calculateAudioMenuX() {
- return consoleCyderFrame.getWidth() - AUDIO_MENU_LABEL_WIDTH - AUDIO_MENU_X_OFFSET;
- }
-
- /**
- * Generates the audio menu label and the button components.
- */
- private void generateAudioMenu() {
- audioControlsLabel = new JLabel();
- audioControlsLabel.setBounds(
- calculateAudioMenuX(),
- -AUDIO_MENU_LABEL_HEIGHT,
- AUDIO_MENU_LABEL_WIDTH,
- AUDIO_MENU_LABEL_HEIGHT);
- audioControlsLabel.setOpaque(true);
- audioControlsLabel.setBackground(CyderColors.getGuiThemeColor());
- audioControlsLabel.setBorder(new LineBorder(Color.black, 5));
- audioControlsLabel.setVisible(false);
- consoleCyderFrame.getIconPane().add(audioControlsLabel, JLayeredPane.MODAL_LAYER);
-
- int currentX = AUDIO_MENU_X_PADDING;
-
- JLabel lastMusicLabel = new JLabel();
- lastMusicLabel.setBounds(currentX, AUDIO_MENU_BUTTON_Y_PADDING,
- AUDIO_MENU_BUTTON_SIZE, AUDIO_MENU_BUTTON_SIZE);
- lastMusicLabel.setIcon(AudioIcons.lastIcon);
- lastMusicLabel.setToolTipText(PREVIOUS);
- lastMusicLabel.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- if (AudioPlayer.isWidgetOpen()) {
- AudioPlayer.handleLastAudioButtonClick();
- }
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- lastMusicLabel.setIcon(AudioIcons.lastIconHover);
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- lastMusicLabel.setIcon(AudioIcons.lastIcon);
- }
- });
- lastMusicLabel.setVisible(true);
- lastMusicLabel.setOpaque(false);
- audioControlsLabel.add(lastMusicLabel);
-
- currentX += AUDIO_MENU_X_PADDING + AUDIO_MENU_BUTTON_SIZE;
-
- playPauseAudioLabel = new JLabel();
- playPauseAudioLabel.setBounds(currentX, AUDIO_MENU_BUTTON_Y_PADDING,
- AUDIO_MENU_BUTTON_SIZE, AUDIO_MENU_BUTTON_SIZE);
- playPauseAudioLabel.setToolTipText(PLAY_PAUSE);
- playPauseAudioLabel.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- if (AudioPlayer.isWidgetOpen()) {
- AudioPlayer.handlePlayPauseButtonClick();
- }
- if (GeneralAudioPlayer.isGeneralAudioPlaying()) {
- GeneralAudioPlayer.stopGeneralAudio();
- }
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- if (GeneralAudioPlayer.generalOrAudioPlayerAudioPlaying()) {
- playPauseAudioLabel.setIcon(AudioIcons.pauseIconHover);
- } else {
- playPauseAudioLabel.setIcon(AudioIcons.playIconHover);
- }
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- if (GeneralAudioPlayer.generalOrAudioPlayerAudioPlaying()) {
- playPauseAudioLabel.setIcon(AudioIcons.pauseIcon);
- } else {
- playPauseAudioLabel.setIcon(AudioIcons.playIcon);
- }
- }
- });
- playPauseAudioLabel.setVisible(true);
- playPauseAudioLabel.setOpaque(false);
- audioControlsLabel.add(playPauseAudioLabel);
-
- revalidateAudioMenuPlayPauseButton();
-
- audioControlsLabel.add(playPauseAudioLabel);
-
- currentX += AUDIO_MENU_X_PADDING + AUDIO_MENU_BUTTON_SIZE;
-
- JLabel nextMusicLabel = new JLabel();
- nextMusicLabel.setBounds(currentX, AUDIO_MENU_BUTTON_Y_PADDING, AUDIO_MENU_BUTTON_SIZE, AUDIO_MENU_BUTTON_SIZE);
- nextMusicLabel.setIcon(AudioIcons.nextIcon);
- audioControlsLabel.add(nextMusicLabel);
- nextMusicLabel.setToolTipText(SKIP);
- nextMusicLabel.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- if (AudioPlayer.isWidgetOpen()) {
- AudioPlayer.handleNextAudioButtonClick();
- }
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- nextMusicLabel.setIcon(AudioIcons.nextIconHover);
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- nextMusicLabel.setIcon(AudioIcons.nextIcon);
- }
- });
- nextMusicLabel.setVisible(true);
- nextMusicLabel.setOpaque(false);
-
- audioControlsLabel.add(nextMusicLabel);
- }
-
- /**
- * Revalidates the background colors of the console menus (audio or taskbar) that are active.
- */
- public void revalidateMenuBackgrounds() {
- if (UiUtil.notNullAndVisible(menuLabel)) {
- menuLabel.setBackground(CyderColors.getGuiThemeColor());
- audioControlsLabel.repaint();
- menuScroll.setBackground(CyderColors.getGuiThemeColor());
- menuScroll.repaint();
- }
-
- if (audioControlsLabel != null && audioControlsLabel.isVisible()) {
- audioControlsLabel.setBackground(CyderColors.getGuiThemeColor());
- audioControlsLabel.repaint();
- }
- }
-
- /**
- * Sets the console to a provided ScreenPosition and moves any pinned CyderFrame windows with it.
- *
- * @param screenPosition the screen position to move the Console to
- */
- public void setLocationOnScreen(ScreenPosition screenPosition) {
- Preconditions.checkNotNull(screenPosition);
-
- consoleCyderFrame.setLocationOnScreen(screenPosition);
-
- getPinnedFrames().forEach(relativeFrame -> UiUtil.requestFramePosition(
- new Point(relativeFrame.xOffset() + consoleCyderFrame.getX(),
- relativeFrame.yOffset() + consoleCyderFrame.getY()),
- relativeFrame.frame()));
- }
-
- /**
- * The record used for frames pinned to the console.
- */
- private record RelativeFrame(CyderFrame frame, int xOffset, int yOffset) {
- }
-
- /**
- * Returns a list of all frames that are pinned to the Console.
- *
- * @return a list of all frames that are pinned to the Console
- */
- private ArrayList getPinnedFrames() {
- ArrayList ret = new ArrayList<>();
-
- ImmutableList.copyOf(UiUtil.getCyderFrames().stream()
- .filter(frame -> frame.isConsole() && !frame.isConsole()
- && GeometryUtil.rectanglesOverlap(consoleCyderFrame.getBounds(), frame.getBounds()))
- .collect(Collectors.toList())).forEach(frame -> {
- int xOffset = frame.getX() - consoleCyderFrame.getX();
- int yOffset = frame.getY() - consoleCyderFrame.getY();
- ret.add(new RelativeFrame(frame, xOffset, yOffset));
- });
-
- return ret;
- }
-
- /**
- * Refreshes the consoleCyderFrame painted title to display the console clock in the specified pattern if enabled.
- */
- public void refreshClockText() {
- boolean showClock = UserDataManager.INSTANCE.shouldDrawConsoleClock();
- if (!showClock) {
- consoleCyderFrame.setCyderFrameTitle("");
- return;
- }
-
- String regularSecondTime = TimeUtil.consoleSecondTime();
- String regularNoSecondTime = TimeUtil.consoleNoSecondTime();
- String userConfiguredTime = TimeUtil.getFormattedTime(
- new SimpleDateFormat(UserDataManager.INSTANCE.getConsoleClockFormat()));
-
- // No custom pattern so take into account showSeconds
- if (userConfiguredTime.equalsIgnoreCase(regularSecondTime)
- || userConfiguredTime.equalsIgnoreCase(regularNoSecondTime)) {
- boolean showSeconds = UserDataManager.INSTANCE.shouldShowConsoleClockSeconds();
- userConfiguredTime = showSeconds ? regularSecondTime : regularNoSecondTime;
- }
-
- consoleCyderFrame.setCyderFrameTitle(userConfiguredTime);
- }
-
- /**
- * Logs out the current user and revokes user management from the {@link UserDataManager}.
- */
- public void logoutCurrentUser() {
- Logger.log(LogTag.LOGOUT, UserDataManager.INSTANCE.getUsername());
- UserDataManager.INSTANCE.setLoggedIn(false);
- UserDataManager.INSTANCE.removeManagement();
- NetworkUtil.terminateHighPingChecker();
- uuid = null;
- }
-
- /**
- * Logs out the current user and shows the login frame
- * relative to the Console's location before it was closed.
- */
- public void logoutCurrentUserAndShowLoginFrame() {
- Point centerPoint = consoleCyderFrame.getCenterPointOnScreen();
- UiUtil.disposeAllFrames(true);
- releaseResourcesAndCloseFrame(false);
- logoutCurrentUser();
- LoginHandler.showGui(centerPoint);
- }
-
- /**
- * Performs the following actions and then exits the program if instructed to:
- *
- * Saves the user's screen stat
- * Stops all audio
- * Deactivates the base input handler
- * Closes the console frame if open
- * Exits the program if invokeExit is true.
- * If the ConsoleFrame is currently open, this occurs after the closing animation completes
- *
- *
- * @param invokeExit whether to invoke a program exit after the above actions
- */
- public void releaseResourcesAndCloseFrame(boolean invokeExit) {
- if (consoleClosed.get()) return;
- consoleClosed.set(true);
-
- saveScreenStat();
- GeneralAudioPlayer.stopAllAudio();
-
- if (baseInputHandler != null) {
- baseInputHandler.deactivate();
- baseInputHandler = null;
- }
-
- if (invokeExit) {
- if (consoleCyderFrame.isDisposed()) {
- OsUtil.exit(ExitCondition.StandardControlledExit);
- } else {
- consoleCyderFrame.addPostCloseAction(() -> OsUtil.exit(ExitCondition.StandardControlledExit));
- consoleCyderFrame.dispose();
- }
- }
- }
-
- /**
- * Returns whether the Console is closed.
- *
- * @return whether the Console is closed
- */
- public boolean isClosed() {
- return consoleClosed.get();
- }
-
- /**
- * Saves the console's position and window stats to the currently logged-in user's json file.
- */
- public void saveScreenStat() {
- if (consoleCyderFrame == null || consoleCyderFrame.isDisposed()) return;
- if (consoleCyderFrame.getState() == UiConstants.FRAME_ICONIFIED) return;
- if (uuid == null) return;
-
- ScreenStat screenStat = UserDataManager.INSTANCE.getScreenStat();
- screenStat.setConsoleWidth(consoleCyderFrame.getWidth());
- screenStat.setConsoleHeight(consoleCyderFrame.getHeight());
- screenStat.setConsoleOnTop(consoleCyderFrame.isAlwaysOnTop());
- screenStat.setMonitor(Integer.parseInt(consoleCyderFrame.getGraphicsConfiguration()
- .getDevice().getIDstring().replaceAll(CyderRegexPatterns.nonNumberRegex, "")));
-
- screenStat.setConsoleX(consoleCyderFrame.getX());
- screenStat.setConsoleY(consoleCyderFrame.getY());
-
- screenStat.setConsoleDirection(consoleDir);
-
- UserDataManager.INSTANCE.setScreenStat(screenStat);
- UserDataManager.INSTANCE.writeUser();
- }
-
- // -------
- // Dancing
- // -------
-
- /**
- * A record for a frame to dance.
- */
- private record RestoreFrame(CyderFrame frame, int restoreX, int restoreY, boolean draggingWasEnabled) {
- /**
- * Restores the encapsulated frame's original location and re-enables
- * dragging if it was enabled prior to dancing.
- */
- public void restore() {
- frame.setLocation(restoreX, restoreY);
-
- if (draggingWasEnabled) {
- frame.enableDragging();
- }
- }
- }
-
- /**
- * Invokes dance in a synchronous way on all CyderFrame instances.
- */
- public void dance() {
- ArrayList restoreFrames = new ArrayList<>();
- UiUtil.getCyderFrames().forEach(frame -> {
- restoreFrames.add(new RestoreFrame(frame, frame.getX(), frame.getY(), frame.isDraggingEnabled()));
- frame.disableDragging();
- });
-
- ProgramStateManager.INSTANCE.setCurrentProgramState(ProgramState.DANCING);
-
- while (ProgramStateManager.INSTANCE.getCurrentProgramState() == ProgramState.DANCING) {
- if (allFramesFinishedDancing()) break;
-
- UiUtil.getCyderFrames().forEach(CyderFrame::danceStep);
- }
-
- stopDancing();
- restoreFrames.forEach(RestoreFrame::restore);
- }
-
- /**
- * Ends the dancing sequence if ongoing.
- */
- public void stopDancing() {
- ProgramStateManager.INSTANCE.setCurrentProgramState(ProgramState.NORMAL);
- UiUtil.getCyderFrames().forEach(CyderFrame::resetDancing);
- }
-
- /**
- * Returns whether all frames have completed a dance iteration.
- *
- * @return whether all frames have completed a dance iteration
- */
- private boolean allFramesFinishedDancing() {
- for (CyderFrame frame : UiUtil.getCyderFrames()) {
- if (!frame.isDancingFinished()) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Sets the background of the console to whatever is behind it.
- * This was the original implementation of frame chams functionality before
- * the windows were actually set to be transparent.
- */
- public void originalChams() {
- try {
- CyderFrame frame = getConsoleCyderFrame();
- Rectangle monitorBounds = frame.getMonitorBounds();
-
- consoleCyderFrame.setVisible(false);
- BufferedImage capture = RobotManager.INSTANCE.getRobot().createScreenCapture(monitorBounds);
- consoleCyderFrame.setVisible(true);
-
- int x = (int) (Math.abs(monitorBounds.getX()) + frame.getX());
- int y = (int) (Math.abs(monitorBounds.getY()) + frame.getY());
- capture = ImageUtil.cropImage(capture, x, y, frame.getWidth(), frame.getHeight());
-
- setBackground(ImageUtil.toImageIcon(capture));
- chamsActive.set(true);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
-
- /**
- * Returns the console's content pane.
- *
- * @return the console's content pane
- */
- public JLabel getConsoleCyderFrameContentPane() {
- return ((JLabel) (consoleCyderFrame.getContentPane()));
- }
-
- /**
- * A semaphore to ensure only one title notification is ever visible.
- */
- private final Semaphore titleNotifyLock = new Semaphore(1);
-
- /**
- * The label used for title notifications.
- */
- private final CyderLabel titleNotifyLabel = new CyderLabel();
-
- /**
- * The minimum acceptable time for a title notify invocation.
- */
- private static final int minimumTitleNotifyVisibleTime = 1000;
-
- /**
- * Paints a label with the provided possibly html-formatted string over the
- * Console for the provided number of milliseconds
- *
- * @param htmlString the string to display, may or may not be formatted using html
- * @param labelFont the font to use for the label
- * @param visibleDuration the duration in ms the notification should be visible for
- */
- public void titleNotify(String htmlString, Font labelFont, Duration visibleDuration) {
- Preconditions.checkNotNull(htmlString);
- Preconditions.checkNotNull(labelFont);
- Preconditions.checkNotNull(visibleDuration);
- Preconditions.checkArgument(visibleDuration.toMillis() > minimumTitleNotifyVisibleTime);
-
- CyderThreadRunner.submit(() -> {
- try {
- titleNotifyLock.acquire();
-
- titleNotifyLabel.setFont(labelFont);
- titleNotifyLabel.setOpaque(true);
- titleNotifyLabel.setVisible(true);
- titleNotifyLabel.setForeground(CyderColors.defaultDarkModeTextColor);
- titleNotifyLabel.setBackground(CyderColors.darkModeBackgroundColor);
-
- BoundsString boundsString = BoundsUtil.widthHeightCalculation(htmlString,
- labelFont, consoleCyderFrame.getWidth());
-
- int containerWidth = boundsString.getWidth();
- int containerHeight = boundsString.getHeight();
-
- if (containerHeight + 2 * titleNotificationPadding > consoleCyderFrame.getHeight()
- || containerWidth + 2 * titleNotificationPadding > consoleCyderFrame.getWidth()) {
- consoleCyderFrame.inform(htmlString, "Console Notification");
- return;
- }
-
- Point center = consoleCyderFrame.getCenterPointOnFrame();
-
- titleNotifyLabel.setText(HtmlUtil.addCenteringToHtml(boundsString.getText()));
- titleNotifyLabel.setBounds(
- (int) (center.getX() - titleNotificationPadding - containerWidth / 2),
- (int) (center.getY() - titleNotificationPadding - containerHeight / 2),
- containerWidth, containerHeight);
- consoleCyderFrame.getContentPane().add(titleNotifyLabel, JLayeredPane.POPUP_LAYER);
- consoleCyderFrame.repaint();
-
- ThreadUtil.sleep(visibleDuration.toMillis());
-
- titleNotifyLabel.setVisible(false);
- consoleCyderFrame.remove(titleNotifyLabel);
- titleNotifyLabel.setText("");
-
- titleNotifyLock.release();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, "Console Title Notify: " + htmlString);
- }
-
- /**
- * Revalidates the bounds of the title label notify if one is underway.
- */
- public void revalidateTitleNotify() {
- if (consoleCyderFrame == null || titleNotifyLabel.getText().isEmpty()) return;
-
- int w = titleNotifyLabel.getWidth();
- int h = titleNotifyLabel.getHeight();
-
- Point center = consoleCyderFrame.getCenterPointOnFrame();
-
- w = (int) (center.getX() - titleNotificationPadding - w / 2);
- h = (int) (center.getY() - titleNotificationPadding - h / 2);
- titleNotifyLabel.setLocation(w, h);
-
- consoleCyderFrame.repaint();
- }
-
- /**
- * Adds the provided frame to {@link #frameTaskbarExceptions}.
- *
- * @param frame the frame to add as an exception
- * @return the hash needed to remove the provided frame from the taskbar exceptions map
- */
- @CanIgnoreReturnValue
- public String addToFrameTaskbarExceptions(CyderFrame frame) {
- Preconditions.checkNotNull(frame);
- Preconditions.checkArgument(!frameTaskbarExceptions.contains(frame));
-
- String hash = SecurityUtil.generateUuid();
- frameTaskbarExceptions.put(hash, frame);
- return hash;
- }
-
- /**
- * Removes the provided frame from {@link #frameTaskbarExceptions} if it is contained.
- *
- * @param securityHash the hash returned when {@link #addToFrameTaskbarExceptions(CyderFrame)} was called
- */
- public void removeFrameTaskbarException(String securityHash) {
- Preconditions.checkNotNull(securityHash);
- Preconditions.checkArgument(!securityHash.isEmpty());
-
- frameTaskbarExceptions.remove(securityHash);
- }
-}
diff --git a/src/main/java/cyder/console/ConsoleBackground.java b/src/main/java/cyder/console/ConsoleBackground.java
deleted file mode 100644
index 1a28d4bc0..000000000
--- a/src/main/java/cyder/console/ConsoleBackground.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package cyder.console;
-
-import com.google.common.base.Preconditions;
-import com.google.errorprone.annotations.Immutable;
-import cyder.exceptions.FatalException;
-import cyder.files.FileUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.ui.frame.CyderFrame;
-import cyder.utils.ImageUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.io.File;
-
-/**
- * A background for the Console.
- */
-@Immutable
-public final class ConsoleBackground {
- /**
- * the file referenced by this object.
- */
- private final File referenceFile;
-
- /**
- * Constructs a new CyderBackground from the provided file if it can be read as an image.
- *
- * @param referenceFile the file to use as the background
- * @throws IllegalArgumentException if the provided file is invalid, null, or does not exist
- */
- public ConsoleBackground(File referenceFile) {
- Preconditions.checkNotNull(referenceFile);
- Preconditions.checkArgument(referenceFile.exists());
- Preconditions.checkArgument(FileUtil.isSupportedImageExtension(referenceFile));
- Preconditions.checkArgument(ImageUtil.isValidImage(referenceFile));
-
- this.referenceFile = referenceFile;
-
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * Returns the file referenced by this object.
- *
- * @return the file referenced by this object
- */
- public File getReferenceFile() {
- return referenceFile;
- }
-
- /**
- * Returns a generated buffered image from the reference file.
- *
- * @return a generated buffered image from the reference file
- */
- public BufferedImage generateBufferedImage() {
- BufferedImage image = null;
-
- try {
- image = ImageUtil.read(referenceFile);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- if (image == null) {
- throw new FatalException("Could not general buffered image from reference file: "
- + referenceFile.getAbsolutePath());
- }
-
- CyderFrame console = Console.INSTANCE.getConsoleCyderFrame();
- if (console != null) {
- Rectangle monitorDimensions = Console.INSTANCE.getConsoleCyderFrame().getMonitorBounds();
- return ImageUtil.ensureFitsInBounds(image,
- new Dimension((int) monitorDimensions.getWidth(), (int) monitorDimensions.getHeight()));
- } else {
- return image;
- }
- }
-
- /**
- * Returns a generated image icon from the background file.
- *
- * @return a generated image icon from the background file
- */
- public ImageIcon generateImageIcon() {
- return ImageUtil.toImageIcon(generateBufferedImage());
- }
-
- /**
- * Generates a scaled image icon.
- *
- * @param width the width of the scaled icon
- * @param height the height of the scaled icon
- * @return the scaled image icon
- */
- public ImageIcon generateScaledImageIcon(int width, int height) {
- return new ImageIcon(generateImageIcon().getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT));
- }
-
- /**
- * Returns whether the reference file still exists, can be read, and is an image.
- *
- * @return whether the reference file still exists, can be read, and is an image
- */
- public boolean isValid() {
- return referenceFile.exists() && generateBufferedImage() != null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- } else if (!(o instanceof ConsoleBackground)) {
- return false;
- }
-
- ConsoleBackground other = (ConsoleBackground) o;
- return getReferenceFile().equals(other.getReferenceFile());
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return referenceFile.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return "ConsoleBackground{referenceFile=" + referenceFile.getAbsolutePath() + "}";
- }
-}
diff --git a/src/main/java/cyder/console/ConsoleConstants.kt b/src/main/java/cyder/console/ConsoleConstants.kt
deleted file mode 100644
index 044b044b7..000000000
--- a/src/main/java/cyder/console/ConsoleConstants.kt
+++ /dev/null
@@ -1,167 +0,0 @@
-package cyder.console
-
-import com.google.common.collect.ImmutableList
-import cyder.enumerations.Direction
-import cyder.props.Props
-import cyder.strings.CyderStrings
-import cyder.utils.StaticUtil
-import java.awt.Dimension
-import java.awt.Font
-import java.io.File
-
-/**
- * Constants used for the [Console].
- */
-internal class ConsoleConstants private constructor() {
- companion object {
- /**
- * The absolute minimum size allowable for the Console.
- */
- @JvmField
- val MINIMUM_SIZE = Dimension(400, 400)
-
- /**
- * The console snap size.
- */
- @JvmField
- val SNAP_SIZE = initializeSnapSize()
-
- /**
- * Returns the value for [.SNAP_SIZE]
- *
- * @return the value for [.SNAP_SIZE]
- */
- private fun initializeSnapSize(): Dimension {
- val len = Props.consoleSnapSize.value
- return Dimension(len, len)
- }
-
- /**
- * The possible audio files to play if the starting user background is grayscale.
- */
- @JvmField
- val GRAYSCALE_AUDIO_PATHS: ImmutableList = ImmutableList.of(
- StaticUtil.getStaticResource("badapple.mp3"),
- StaticUtil.getStaticResource("beetlejuice.mp3"),
- StaticUtil.getStaticResource("blackorwhite.mp3"))
-
- /**
- * The thickness of the border around the input field and output area when enabled.
- */
- const val FIELD_BORDER_THICKNESS = 3
-
- /**
- * The default console direction.
- */
- @JvmField
- val DEFAULT_CONSOLE_DIRECTION = Direction.TOP
-
- /**
- * The prefix for the input field bash string.
- */
- const val BASH_STRING_PREFIX = "@Cyder:~$" + CyderStrings.space
-
- /**
- * The horizontal padding between the input/output fields and the frame bounds.
- */
- const val FIELD_X_PADDING = 15
-
- /**
- * The vertical padding between the input and output fields and the frame bounds.
- */
- const val FIELD_Y_PADDING = 15
-
- /**
- * The height of the input field.
- */
- const val INPUT_FIELD_HEIGHT = 100
-
- /**
- * The input map focus key to allow drag label buttons to be triggered via the enter key.
- */
- const val BUTTON_INPUT_FOCUS_MAP_KEY = "Button.focusInputMap"
-
- /**
- * The pressed keyword for input focus mapping.
- */
- const val PRESSED = "pressed"
-
- /**
- * The released keyword for input focus mapping.
- */
- const val RELEASED = "released"
-
- /**
- * The enter keyword for input focus mapping.
- */
- const val ENTER = "ENTER"
-
- /**
- * The released enter keyword for input focus mapping.
- */
- const val RELEASED_ENTER = RELEASED + CyderStrings.space + ENTER
-
- /**
- * The width of the taskbar menu label.
- */
- const val TASKBAR_MENU_WIDTH = 110
-
- /**
- * The keycode used to detect the f17 key being pressed and invoke the easter egg.
- */
- const val F_17_KEY_CODE = 17
-
- /**
- * The offset for special function key codes and normal ones.
- */
- const val SPECIAL_FUNCTION_KEY_CODE_OFFSET = 13
-
- /**
- * The fullscreen timeout between background animation increments.
- */
- const val fullscreenBackgroundAnimationTimeout = 1
-
- /**
- * The fullscreen increment for background animations.
- */
- const val fullscreenBackgroundAnimationIncrement = 20
-
- /**
- * The default timeout between background animation increments.
- */
- const val defaultBackgroundAnimationTimeout = 5
-
- /**
- * The default increment for background animations.
- */
- const val defaultBackgroundAnimationIncrement = 8
-
- /**
- * The x,y padding value for title notifications.
- */
- const val titleNotificationPadding = 20
-
- /**
- * The font used for the clock label.
- */
- @JvmField
- val CONSOLE_CLOCK_FONT = initializeConsoleClockFont()
-
- /**
- * Returns the font for the console clock.
- *
- * @return the font for the console clock
- */
- private fun initializeConsoleClockFont(): Font {
- val fontName = Props.consoleClockFontName.value
- val fontSize = Props.consoleClockFontSize.value
- return Font(fontName, Font.BOLD, fontSize)
- }
-
- /**
- * The music file for the f17 easter egg.
- */
- @JvmField
- val F_17_MUSIC_FILE = StaticUtil.getStaticResource("f17.mp3")!!
- }
-}
\ No newline at end of file
diff --git a/src/main/java/cyder/console/TaskbarIcon.java b/src/main/java/cyder/console/TaskbarIcon.java
deleted file mode 100644
index 330fb4434..000000000
--- a/src/main/java/cyder/console/TaskbarIcon.java
+++ /dev/null
@@ -1,515 +0,0 @@
-package cyder.console;
-
-import com.google.common.base.Preconditions;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.exceptions.IllegalMethodException;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.ui.label.CyderLabel;
-import cyder.utils.ImageUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.image.BufferedImage;
-import java.awt.image.RescaleOp;
-import java.util.Objects;
-
-/**
- * A {@link Console} taskbar icon for the console menu.
- */
-public class TaskbarIcon {
- /**
- * The length of the taskbar icons generated.
- */
- private static final int ICON_LEN = 75;
-
- /**
- * The border length of the taskbar icons generated.
- */
- private static final int BORDER_LEN = 5;
-
- /**
- * The maximum number of characters allowed for a compact taskbar icon.
- */
- private static final int MAX_COMPACT_LABEL_CHARS = 10;
-
- /**
- * The color for custom painted taskbar icon borders.
- */
- private static final Color BORDER_COLOR = Color.black;
-
- /**
- * The font used for taskbar icon painted names.
- */
- private static final Font labelFont = new Font("Agency FB", Font.BOLD, 28);
-
- /**
- * The factor to darken a buffered image by for hover/focus events.
- */
- private static final float MAX_DARK_FACTOR = 0.7f;
-
- /**
- * The rescale operator used to darken buffered images.
- */
- private static final RescaleOp rescaleOp = new RescaleOp(MAX_DARK_FACTOR, 0, null);
-
- /**
- * The maximum number of characters allowed for a non-compact taskbar icon.
- */
- private static final int MAX_NON_COMPACT_LABEL_CHARS = 4;
-
- /**
- * The actual icon used for the console taskbar.
- */
- private JLabel taskbarIcon;
-
- /**
- * The builder last used to construct the encapsulated taskbar icon.
- */
- private final Builder builder;
-
- /**
- * Suppress default constructor.
- */
- private TaskbarIcon() {
- throw new IllegalMethodException(CyderStrings.ILLEGAL_CONSTRUCTOR);
- }
-
- /**
- * Constructs and generates a new taskbar icon.
- *
- * @param builder the builder to construct the taskbar icon from
- */
- private TaskbarIcon(Builder builder) {
- Preconditions.checkNotNull(builder.getName());
- Preconditions.checkArgument(!builder.getName().isEmpty());
-
- Logger.log(LogTag.OBJECT_CREATION, this);
-
- this.builder = builder;
-
- generateTaskbarIcon(builder);
- }
-
- /**
- * Regenerates the taskbar icon based on the current builder's properties.
- */
- public void generateTaskbarIcon() {
- generateTaskbarIcon(builder);
- }
-
- /**
- * Generates the taskbar icon for a CyderFrame based on the provided properties.
- *
- * @param builder the TaskbarIcon builder to construct the TaskbarIcon from
- */
- private void generateTaskbarIcon(Builder builder) {
- Preconditions.checkNotNull(builder.getName());
- Preconditions.checkArgument(!builder.getName().isEmpty());
-
- if (builder.isCompact()) {
- generateCompactTaskbarIcon(builder);
- } else {
- generateNonCompactTaskbarIcon(builder);
- }
- }
-
- /**
- * Generates and returns the compact taskbar icon.
- *
- * @param builder the builder to construct the compact taskbar icon from
- */
- private void generateCompactTaskbarIcon(Builder builder) {
- String name = builder.getName().substring(0, Math.min(MAX_COMPACT_LABEL_CHARS, builder.getName().length()));
-
- JLabel compactTaskbarLabel = new JLabel(name);
- compactTaskbarLabel.setForeground(builder.isFocused() ? CyderColors.regularRed : CyderColors.vanilla);
- compactTaskbarLabel.setFont(CyderFonts.DEFAULT_FONT_SMALL);
- compactTaskbarLabel.setVerticalAlignment(SwingConstants.CENTER);
- compactTaskbarLabel.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- builder.getRunnable().run();
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- compactTaskbarLabel.setForeground(
- builder.isFocused() ? CyderColors.vanilla : CyderColors.regularRed);
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- compactTaskbarLabel.setForeground(
- builder.isFocused() ? CyderColors.regularRed : CyderColors.vanilla);
- }
- });
- compactTaskbarLabel.setToolTipText(builder.getName());
-
- taskbarIcon = compactTaskbarLabel;
- }
-
- /**
- * Generates and returns the non-compact taskbar icon.
- *
- * @param builder the builder to construct the non-compact taskbar icon from
- */
- private void generateNonCompactTaskbarIcon(Builder builder) {
- BufferedImage paintedImage;
- if (builder.getCustomIcon() != null) {
- paintedImage = ImageUtil.resizeImage(ICON_LEN, ICON_LEN, builder.getCustomIcon());
- } else {
- paintedImage = new BufferedImage(ICON_LEN, ICON_LEN, BufferedImage.TYPE_INT_RGB);
- Graphics g = paintedImage.getGraphics();
- g.setColor(BORDER_COLOR);
- g.fillRect(0, 0, ICON_LEN, BORDER_LEN);
- g.fillRect(0, 0, BORDER_LEN, ICON_LEN);
- g.fillRect(ICON_LEN - BORDER_LEN, 0, ICON_LEN, ICON_LEN);
- g.fillRect(0, ICON_LEN - BORDER_LEN, ICON_LEN, ICON_LEN);
- }
-
- paintBorderOnImage(paintedImage);
-
- ImageIcon defaultIcon = new ImageIcon(paintedImage);
- ImageIcon focusIcon = new ImageIcon(rescaleOp.filter(paintedImage, null));
-
- JLabel nonCompactTaskbarLabel = new JLabel();
- nonCompactTaskbarLabel.setSize(ICON_LEN, ICON_LEN);
- nonCompactTaskbarLabel.setIcon(builder.isFocused() ? focusIcon : defaultIcon);
-
- String name = builder.getName().trim();
- String labelName = name.substring(0, Math.min(MAX_NON_COMPACT_LABEL_CHARS, name.length())).trim();
-
- CyderLabel titleLabel = new CyderLabel(builder.getCustomIcon() == null ? labelName : "");
- titleLabel.setFont(labelFont);
- titleLabel.setForeground(CyderColors.vanilla);
- titleLabel.setBounds(0, 0, ICON_LEN, ICON_LEN);
- titleLabel.setFocusable(false);
- titleLabel.setToolTipText(builder.getName());
- titleLabel.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- if (builder.getRunnable() != null) {
- builder.getRunnable().run();
- }
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- nonCompactTaskbarLabel.setIcon(builder.isFocused() ? defaultIcon : focusIcon);
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- nonCompactTaskbarLabel.setIcon(builder.isFocused() ? focusIcon : defaultIcon);
- }
- });
- nonCompactTaskbarLabel.add(titleLabel);
-
- taskbarIcon = nonCompactTaskbarLabel;
- }
-
- /**
- * Paints the taskbar border on the provided image.
- *
- * @param image the image to paint the border on
- */
- private void paintBorderOnImage(BufferedImage image) {
- Graphics g = image.getGraphics();
- g.setColor(builder.getCustomIcon() == null ? builder.getBorderColor() : BORDER_COLOR);
- g.fillRect(0, 0, BORDER_LEN, ICON_LEN);
- g.fillRect(0, 0, ICON_LEN, BORDER_LEN);
- g.fillRect(ICON_LEN - 5, 0, ICON_LEN, ICON_LEN);
- g.fillRect(0, ICON_LEN - 5, ICON_LEN, ICON_LEN);
- }
-
- /**
- * Returns the generated taskbar icon.
- *
- * @return the generated taskbar icon
- */
- public JLabel getTaskbarIcon() {
- return taskbarIcon;
- }
-
- /**
- * Sets whether this taskbar icon is focused.
- *
- * @param focused whether this taskbar icon is focused
- */
- public void setFocused(boolean focused) {
- this.builder.setFocused(focused);
- }
-
- /**
- * Runs the runnable associated with this taskbar icon.
- */
- public void runRunnable() {
- this.builder.getRunnable().run();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return "TaskbarIcon{"
- + "taskbarIcon=" + taskbarIcon
- + ", builder=" + builder
- + "}";
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- } else if (!(o instanceof TaskbarIcon)) {
- return false;
- }
-
- TaskbarIcon other = (TaskbarIcon) o;
- return Objects.equals(builder, other.builder);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return builder.hashCode();
- }
-
- /**
- * A builder for a {@link TaskbarIcon}.
- */
- public static final class Builder {
- /**
- * Whether this icon should be compact.
- */
- private boolean compact;
-
- /**
- * Whether this icon is focused.
- */
- private boolean focused;
-
- /**
- * The border color.
- */
- private Color borderColor;
-
- /**
- * A possible custom icon.
- */
- private ImageIcon customIcon;
-
- /**
- * The runnable to invoke upon a click action.
- */
- private Runnable runnable;
-
- /**
- * The name of the icon.
- */
- private final String name;
-
- /**
- * Constructs a new builder for a taskbar icon.
- *
- * @param name the name/tooltip for the taskbar icon
- */
- public Builder(String name) {
- Preconditions.checkNotNull(name);
- Preconditions.checkArgument(!name.isEmpty());
-
- this.name = name;
- }
-
- /**
- * Sets whether this taskbar icon should be painted in compact mode.
- *
- * @param compact whether this taskbar icon should be painted in compact mode
- * @return this Builder
- */
- @CanIgnoreReturnValue
- public Builder setCompact(boolean compact) {
- this.compact = compact;
- return this;
- }
-
- /**
- * Sets whether this taskbar icon should be painted as focused.
- *
- * @param focused whether this taskbar icon should be painted as focused
- * @return this Builder
- */
- @CanIgnoreReturnValue
- public Builder setFocused(boolean focused) {
- this.focused = focused;
- return this;
- }
-
- /**
- * Sets the borderColor for this taskbar icon.
- *
- * @param borderColor the name for this taskbar icon
- * @return this Builder
- */
- @CanIgnoreReturnValue
- public Builder setBorderColor(Color borderColor) {
- Preconditions.checkNotNull(borderColor);
-
- this.borderColor = borderColor;
- return this;
- }
-
- /**
- * Sets the customIcon for this taskbar icon.
- *
- * @param customIcon the name for this taskbar icon
- * @return this Builder
- */
- @CanIgnoreReturnValue
- public Builder setCustomIcon(ImageIcon customIcon) {
- Preconditions.checkNotNull(customIcon);
-
- this.customIcon = customIcon;
- return this;
- }
-
- /**
- * Sets the runnable for this taskbar icon.
- *
- * @param runnable the runnable for this taskbar icon
- * @return this Builder
- */
- @CanIgnoreReturnValue
- public Builder setRunnable(Runnable runnable) {
- Preconditions.checkNotNull(runnable);
-
- this.runnable = runnable;
- return this;
- }
-
- /**
- * Returns whether this icon should be generated as compact.
- *
- * @return whether this icon should be generated as compact
- */
- public boolean isCompact() {
- return compact;
- }
-
- /**
- * Returns whether this icon should be generated as focused.
- *
- * @return whether this icon should be generated as focused
- */
- public boolean isFocused() {
- return focused;
- }
-
- /**
- * Returns the border color for this icon.
- *
- * @return the border color for this icon
- */
- public Color getBorderColor() {
- return borderColor;
- }
-
- /**
- * Returns the custom icon for this icon.
- *
- * @return the custom icon for this icon
- */
- public ImageIcon getCustomIcon() {
- return customIcon;
- }
-
- /**
- * Returns the runnable for this icon.
- *
- * @return the runnable for this icon
- */
- public Runnable getRunnable() {
- return runnable;
- }
-
- /**
- * Returns the name and tooltip of this icon.
- *
- * @return the name and tooltip of this icon
- */
- public String getName() {
- return name;
- }
-
- /**
- * Constructs a new TaskbarIcon instance using this builder's members.
- *
- * @return a new TaskbarIcon instance using this builder's members
- */
- public TaskbarIcon build() {
- return new TaskbarIcon(this);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- } else if (!(o instanceof Builder)) {
- return false;
- }
-
- Builder other = (Builder) o;
-
- return other.isCompact() == compact
- && other.isFocused() == focused
- && Objects.equals(other.getBorderColor(), borderColor)
- && Objects.equals(other.getCustomIcon(), customIcon)
- && Objects.equals(other.getRunnable(), runnable)
- && Objects.equals(other.getName(), name);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- int ret = Boolean.hashCode(compact);
- ret = 31 * ret + Boolean.hashCode(focused);
- ret = 31 * ret + Objects.hashCode(borderColor);
- ret = 31 * ret + Objects.hashCode(customIcon);
- ret = 31 * ret + Objects.hashCode(runnable);
- ret = 31 * ret + Objects.hashCode(name);
- return ret;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return "TaskbarIconBuilder{"
- + "compact: " + compact
- + ", focused: " + focused
- + ", borderColor: " + borderColor
- + ", customIcon: " + customIcon
- + ", runnable: " + runnable
- + ", name: \"" + name + "\""
- + "}";
- }
- }
-}
diff --git a/src/main/java/cyder/console/package-info.java b/src/main/java/cyder/console/package-info.java
deleted file mode 100644
index bbbe9876a..000000000
--- a/src/main/java/cyder/console/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Classes related to the console and the taskbar.
- */
-package cyder.console;
diff --git a/src/main/java/cyder/games/HangmanGame.java b/src/main/java/cyder/games/HangmanGame.java
deleted file mode 100644
index a59576738..000000000
--- a/src/main/java/cyder/games/HangmanGame.java
+++ /dev/null
@@ -1,323 +0,0 @@
-package cyder.games;
-
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.*;
-import cyder.constants.CyderFonts;
-import cyder.constants.CyderRegexPatterns;
-import cyder.enumerations.CyderInspection;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.math.NumberUtil;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.label.CyderLabel;
-import cyder.utils.StaticUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.util.ArrayList;
-
-/**
- * A java implementation of the classic Hangman game.
- */
-@CyderAuthor
-@Vanilla
-@SuppressCyderInspections(CyderInspection.VanillaInspection)
-public final class HangmanGame {
- /**
- * The frame object.
- */
- private static CyderFrame hangmanFrame;
-
- /**
- * The current word.
- */
- private static String hangmanWord;
-
- /**
- * The reset button.
- */
- private static CyderButton resetButton;
-
- /**
- * The field the user enters a letter in.
- */
- private static CyderTextField letterField;
-
- /**
- * The label the current hangman image is appended to
- */
- private static JLabel imageLabel;
-
- /**
- * The label displaying the current hangman word.
- */
- private static CyderLabel currentWordLabel;
-
- /**
- * The number of wrong guesses.
- */
- private static int numWrongGuesses;
-
- /**
- * The letters that have been already guessed.
- */
- private static final ArrayList chosenLetters = new ArrayList<>();
-
- /**
- * The placeholder used for the characters on the current word label.
- */
- private static final String wordLabelCharPlaceholder = " _ ";
-
- /**
- * The name of the file containing the hangman words.
- */
- private static final String wordsFile = "hangman.txt";
-
- /**
- * The list of words used for hangman.
- */
- private static final ImmutableList words;
-
- static {
- ArrayList ret = new ArrayList<>();
-
- try (BufferedReader reader = new BufferedReader(new FileReader(StaticUtil.getStaticPath(wordsFile)))) {
- String line;
- while ((line = reader.readLine()) != null) {
- if (!line.trim().isEmpty()) {
- ret.add(line);
- }
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- words = ImmutableList.copyOf(ret);
- }
-
- /**
- * The reset text for the reset button.
- */
- private static final String RESET = "Reset";
-
- /**
- * The play again text for the reset button.
- */
- private static final String PLAY_AGAIN = "Play again";
-
- /**
- * The default hangman icon.
- */
- private static final ImageIcon defaultHangmanIcon = new ImageIcon(StaticUtil.getStaticPath("hangman.png"));
-
- /**
- * The frame title.
- */
- private static final String HANGMAN = "Hangman";
-
- /**
- * The width of the hangman frame.
- */
- private static final int FRAME_WIDTH = 600;
-
- /**
- * The height of the hangman frame.
- */
- private static final int FRAME_HEIGHT = 800;
-
- /**
- * The font for the word label.
- */
- private static final Font wordLabelFont = CyderFonts.SEGOE_30.deriveFont(26f);
-
- /**
- * The length of the image label.
- */
- private static final int imageLabelLen = 512;
-
- /**
- * The spacing partition between components.
- */
- private static final int spacingLen = 3;
-
- /**
- * The height of the primary components, not including the image label.
- */
- private static final int componentHeight = 40;
-
- /**
- * The maximum number of wrong guesses a user can make.
- */
- private static final int maxNumWrongGuesses = 8;
-
- /**
- * Suppress default constructor.
- */
- private HangmanGame() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Widget(triggers = "hangman", description = "A hangman game")
- public static void showGui() {
- UiUtil.closeIfOpen(hangmanFrame);
-
- hangmanFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(HANGMAN)
- .build();
-
- CyderPartitionedLayout partitionedLayout = new CyderPartitionedLayout();
-
- currentWordLabel = new CyderLabel();
- currentWordLabel.setHorizontalAlignment(SwingConstants.CENTER);
- currentWordLabel.setFont(wordLabelFont);
- currentWordLabel.setSize(imageLabelLen, 2 * componentHeight);
- partitionedLayout.addComponentMaintainSize(currentWordLabel);
-
- partitionedLayout.spacer(spacingLen);
-
- imageLabel = new JLabel();
- imageLabel.setIcon(defaultHangmanIcon);
- imageLabel.setSize(imageLabelLen, imageLabelLen);
- partitionedLayout.addComponentMaintainSize(imageLabel);
-
- partitionedLayout.spacer(spacingLen);
-
- letterField = new CyderTextField();
- letterField.setHorizontalAlignment(JTextField.CENTER);
- letterField.setBackground(Color.white);
- letterField.setKeyEventRegexMatcher(CyderRegexPatterns.englishLettersRegex);
- letterField.setToolTipText("Enter your letter guess here");
- letterField.addKeyListener(new KeyListener() {
- @Override
- public void keyTyped(KeyEvent e) {
- onLetterFieldKeyAction(e);
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- onLetterFieldKeyAction(e);
- }
-
- @Override
- public void keyReleased(KeyEvent e) {
- onLetterFieldKeyAction(e);
- }
- });
- letterField.setSize(imageLabelLen, componentHeight);
- partitionedLayout.addComponentMaintainSize(letterField);
-
- partitionedLayout.spacer(spacingLen);
-
- resetButton = new CyderButton(RESET);
- resetButton.addActionListener(e -> setup());
- resetButton.setSize(imageLabelLen, componentHeight);
- partitionedLayout.addComponentMaintainSize(resetButton);
-
- hangmanFrame.setCyderLayout(partitionedLayout);
- hangmanFrame.finalizeAndShow();
- letterField.requestFocus();
-
- setup();
- }
-
- /**
- * The logic to be invoked on any key event that occurs in the letter field.
- *
- * @param e the key event
- */
- @ForReadability
- private static void onLetterFieldKeyAction(KeyEvent e) {
- char code = e.getKeyChar();
- if (code == KeyEvent.VK_DELETE || code == KeyEvent.VK_BACK_SPACE) {
- e.consume();
- Toolkit.getDefaultToolkit().beep();
- return;
- } else if (!Character.isAlphabetic(code)) {
- e.consume();
- Toolkit.getDefaultToolkit().beep();
- return;
- }
-
- letterField.setText("");
- letterChosen(code);
- }
-
- /**
- * Sets up the hangman game.
- */
- private static void setup() {
- resetButton.setText(RESET);
- letterField.setEnabled(true);
- chosenLetters.clear();
- chooseHangmanWord();
-
- currentWordLabel.setText(StringUtil.fillString(hangmanWord.length(), wordLabelCharPlaceholder));
- imageLabel.setIcon(defaultHangmanIcon);
-
- numWrongGuesses = 0;
- }
-
- /**
- * Chooses a new hangman word.
- */
- private static void chooseHangmanWord() {
- hangmanWord = words.get(NumberUtil.generateRandomInt(words.size() - 1)).toLowerCase();
- }
-
- /**
- * Performs the actions necessary when a letter is chosen.
- *
- * @param chosenLetter the chosen letter
- */
- private static void letterChosen(char chosenLetter) {
- String letter = String.valueOf(chosenLetter);
- if (chosenLetters.contains(letter)) return;
-
- chosenLetters.add(letter);
-
- if (hangmanWord.toLowerCase().contains(letter)) {
- char[] wordChars = hangmanWord.toCharArray();
- StringBuilder labelTextBuilder = new StringBuilder();
-
- for (char currentLetter : wordChars) {
- if (chosenLetters.contains(String.valueOf(currentLetter))) {
- labelTextBuilder.append(currentLetter);
- } else {
- labelTextBuilder.append(wordLabelCharPlaceholder);
- }
- }
-
- String labelText = labelTextBuilder.toString();
- if (labelText.equalsIgnoreCase(hangmanWord)) {
- currentWordLabel.setText("You guessed the word \"" + hangmanWord + "\" Would you like to start again?");
- letterField.setEnabled(false);
- resetButton.setText(PLAY_AGAIN);
- } else {
- currentWordLabel.setText(labelText);
- }
- } else {
- numWrongGuesses++;
- imageLabel.setIcon(StaticUtil.getImageIcon(
- "hangman" + numWrongGuesses + Extension.PNG.getExtension()));
- if (numWrongGuesses == maxNumWrongGuesses) {
- currentWordLabel.setText("Game over! You were unable to guess \"" + hangmanWord
- + "\" Would you like to start again?");
- resetButton.setText(PLAY_AGAIN);
- letterField.setEnabled(false);
- }
- }
- }
-}
diff --git a/src/main/java/cyder/games/TttGame.java b/src/main/java/cyder/games/TttGame.java
deleted file mode 100644
index 47c72d9a0..000000000
--- a/src/main/java/cyder/games/TttGame.java
+++ /dev/null
@@ -1,329 +0,0 @@
-package cyder.games;
-
-import com.google.common.collect.Range;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.SuppressCyderInspections;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.enumerations.CyderInspection;
-import cyder.exceptions.IllegalMethodException;
-import cyder.getter.GetInputBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.layouts.CyderGridLayout;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.drag.CyderDragLabel;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.pane.CyderPanel;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.util.Optional;
-
-/**
- * A tic tac toe game widget.
- */
-@CyderAuthor
-@Vanilla
-@SuppressCyderInspections(CyderInspection.VanillaInspection)
-public final class TttGame {
- /**
- * The CyderFrame instance to use to ensure no other games exist with one Cyder instance.
- */
- private static CyderFrame tttFrame;
-
- /**
- * The buttons for the board.
- */
- private static CyderButton[][] boardButtons;
-
- /**
- * The foreground color used for the buttons.
- */
- public static final Color blueForeground = new Color(71, 81, 117);
-
- /**
- * Player enums.
- */
- private enum Player {
- X, O
- }
-
- /**
- * The current player.
- */
- private static Player currentPlayer;
-
- /**
- * The information label.
- */
- private static JLabel infoLabel;
-
- /**
- * The range of allowable values for tic tac toe.
- */
- private static final Range GRID_SIZE_RANGE = Range.closed(3, 11);
-
- /**
- * Suppress default constructor.
- */
- private TttGame() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- private static final Dimension buttonSize = new Dimension(60, 60);
- private static int boardLength = 5;
- private static final LineBorder buttonBorder = new LineBorder(CyderColors.navy, 5, false);
- private static final int buttonPadding = 10;
-
- @SuppressCyderInspections(CyderInspection.WidgetInspection)
- @Widget(triggers = {"ttt", "tic tac toe"}, description = "A TicTacToe widget")
- public static void showGui() {
- UiUtil.closeIfOpen(tttFrame);
-
- int labelOffset = 60;
- int frameLen = buttonSize.width * boardLength + buttonPadding * (boardLength + 2) + labelOffset;
-
- tttFrame = new CyderFrame.Builder()
- .setWidth(frameLen)
- .setHeight(frameLen)
- .setTitle("TicTacToe")
- .build();
- tttFrame.addMenuItem("Board Size", () -> CyderThreadRunner.submit(() -> {
- try {
- Optional optionalSizeString = GetterUtil.getInstance().getInput(
- new GetInputBuilder("Board Size", String.valueOf(boardLength))
- .setFieldRegex("[0-7]")
- .setRelativeTo(tttFrame));
- if (optionalSizeString.isEmpty()) return;
- String sizeString = optionalSizeString.get();
-
- try {
- int newBoardLength = Integer.parseInt(sizeString);
-
- if (GRID_SIZE_RANGE.contains(newBoardLength)) {
- boardLength = newBoardLength;
- showGui();
- } else {
- tttFrame.notify("Sorry, but " + newBoardLength
- + " is not in the allowable range of ["
- + GRID_SIZE_RANGE.lowerEndpoint() + ", "
- + GRID_SIZE_RANGE.upperEndpoint() + CyderStrings.closingBracket);
- }
- } catch (Exception ignored) {
- tttFrame.notify("Unable to parse input as an integer");
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, "Board Size Changer"));
- tttFrame.addMenuItem("Reset Board", TttGame::resetBoard);
- tttFrame.setMenuButtonShown(true);
-
- infoLabel = new JLabel();
- infoLabel.setHorizontalAlignment(JLabel.CENTER);
- infoLabel.setFont(CyderFonts.DEFAULT_FONT);
- infoLabel.setForeground(CyderColors.navy);
- infoLabel.setBounds(0, CyderDragLabel.DEFAULT_HEIGHT, frameLen, labelOffset);
- tttFrame.getContentPane().add(infoLabel);
-
- boardButtons = new CyderButton[boardLength][boardLength];
-
- CyderGridLayout buttonGridLayout = new CyderGridLayout(boardLength, boardLength);
-
- for (int y = 0 ; y < boardLength ; y++) {
- for (int x = 0 ; x < boardLength ; x++) {
- CyderButton button = new CyderButton("");
- button.setPreferredSize(buttonSize);
- button.setBackground(CyderColors.vanilla);
- button.setFocusPainted(false);
- button.setBackground(CyderColors.vanilla);
- button.setFont(CyderFonts.SEGOE_30);
- button.setBorder(buttonBorder);
- button.addActionListener(e -> {
- if (button.getText().isEmpty()) {
- if (currentPlayer == Player.X) {
- button.setText("X");
- button.setFont(CyderFonts.SEGOE_30);
- currentPlayer = Player.O;
-
- } else {
- button.setText("O");
- button.setForeground(blueForeground);
- button.setFont(CyderFonts.SEGOE_30);
- currentPlayer = Player.X;
- }
-
- updateTurnLabel();
- checkForWin();
- }
- });
-
- button.setSize(buttonSize.width, buttonSize.height);
- buttonGridLayout.addComponent(button, x, y);
- boardButtons[y][x] = button;
- }
- }
-
- CyderPanel panel = new CyderPanel(buttonGridLayout);
- panel.setBounds(0, CyderDragLabel.DEFAULT_HEIGHT + labelOffset - 10,
- frameLen, frameLen - (CyderDragLabel.DEFAULT_HEIGHT + labelOffset));
- tttFrame.getContentPane().add(panel);
-
- tttFrame.finalizeAndShow();
- panel.revalidateComponents();
-
- currentPlayer = Player.X;
-
- updateTurnLabel();
- }
-
- /**
- * Updates the player turn label.
- */
- private static void updateTurnLabel() {
- infoLabel.setText("Player Turn: " + (currentPlayer == Player.X ? "X" : "O"));
- }
-
- /**
- * Resets the ttt board
- */
- private static void resetBoard() {
- currentPlayer = Player.X;
- updateTurnLabel();
-
- for (CyderButton[] buttonRow : boardButtons) {
- for (CyderButton button : buttonRow) {
- button.setText("");
- }
- }
- }
-
- /**
- * Checks for a game win.
- */
- private static void checkForWin() {
- if (checkPlayerWin("X")) {
- tttFrame.notify("X's have won the game! Congratulations!");
- resetBoard();
- } else if (checkPlayerWin("O")) {
- tttFrame.notify("O's have won the game! Congratulations!");
- resetBoard();
- } else if (isBoardFull()) {
- tttFrame.notify("The game ended with no winners.");
- resetBoard();
- }
- }
-
- /**
- * Returns whether the provided player has won the game.
- *
- * @param player the player to check for winning
- * @return whether the provided player has won
- */
- private static boolean checkPlayerWin(String player) {
- return isHorizontalWin(player) || isVerticalWin(player) || isDiagonalWin(player);
- }
-
- /**
- * Returns whether the provided player has won via a horizontal win.
- *
- * @param player the player to test for a horizontal win
- * @return whether the provided player has won via a horizontal win
- */
- private static boolean isHorizontalWin(String player) {
- for (int y = 0 ; y < boardLength ; y++) {
- boolean line = true;
-
- for (int x = 0 ; x < boardLength ; x++) {
- line = line && boardButtons[y][x].getText().equals(player);
- }
-
- if (line) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the provided player has won via a vertical win.
- *
- * @param player the player to test for a vertical win
- * @return whether the provided player has won via a vertical win
- */
- private static boolean isVerticalWin(String player) {
- CyderButton[][] rotated = new CyderButton[boardLength][boardLength];
-
- for (int i = 0 ; i < boardButtons[0].length ; i++) {
- for (int j = boardButtons.length - 1 ; j >= 0 ; j--) {
- rotated[i][j] = boardButtons[j][i];
- }
- }
-
- for (int y = 0 ; y < boardLength ; y++) {
- boolean line = true;
-
- for (int x = 0 ; x < boardLength ; x++) {
- line = line && rotated[y][x].getText().equals(player);
- }
-
- if (line) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the provided player has won via a diagonal win.
- *
- * @param player the player to test for a diagonal win
- * @return whether the provided player has won via a diagonal win
- */
- private static boolean isDiagonalWin(String player) {
- boolean topLeftBottomRight = true;
-
- for (int i = 0 ; i < boardLength ; i++) {
- topLeftBottomRight = topLeftBottomRight && boardButtons[i][i].getText().equals(player);
- }
-
- if (topLeftBottomRight) {
- return true;
- }
-
- boolean topRightBottomLeft = true;
-
- for (int i = 0 ; i < boardLength ; i++) {
- topRightBottomLeft =
- topRightBottomLeft && boardButtons[boardLength - i - 1][i].getText().equals(player);
- }
-
- return topRightBottomLeft;
- }
-
- /**
- * Returns whether the board is full.
- *
- * @return whether the board is full
- */
- private static boolean isBoardFull() {
- for (CyderButton[] buttonRow : boardButtons) {
- for (CyderButton button : buttonRow) {
- if (button.getText().isEmpty()) {
- return false;
- }
- }
- }
-
- return true;
- }
-}
diff --git a/src/main/java/cyder/games/package-info.java b/src/main/java/cyder/games/package-info.java
deleted file mode 100644
index ec5d2ac97..000000000
--- a/src/main/java/cyder/games/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Simple games implemented in Cyder.
- */
-package cyder.games;
diff --git a/src/main/java/cyder/handlers/external/DirectoryViewer.java b/src/main/java/cyder/handlers/external/DirectoryViewer.java
deleted file mode 100644
index 3c14e959c..000000000
--- a/src/main/java/cyder/handlers/external/DirectoryViewer.java
+++ /dev/null
@@ -1,303 +0,0 @@
-package cyder.handlers.external;
-
-import com.google.common.base.Preconditions;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.list.CyderScrollList;
-import cyder.utils.OsUtil;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Stack;
-
-/**
- * A directory navigation widget.
- */
-public final class DirectoryViewer {
- /**
- * The frame for the directory widget.
- */
- private static CyderFrame directoryFrame;
-
- /**
- * The field to display the current directory and to allow manual paths to be entered.
- */
- private static CyderTextField directoryField;
-
- /**
- * The directory scroll label. Needed to allow removal when files are changed.
- */
- private static JLabel dirScrollLabel = new JLabel();
-
- /**
- * The current files.
- */
- private static final ArrayList currentFiles = new ArrayList<>();
-
- /**
- * Stack to traverse backwards through history of viewed directories.
- */
- private static final Stack backward = new Stack<>();
-
- /**
- * Stack to traverse forward through history of viewed directories.
- */
- private static final Stack forward = new Stack<>();
-
- /**
- * The current location of the directory widget.
- */
- private static File currentDirectory;
-
- /**
- * The width of the scroll view.
- */
- private static final int SCROLL_WIDTH = 600;
-
- /**
- * The height of the scroll view.
- */
- private static final int SCROLL_HEIGHT = 400;
-
- /**
- * The scroll list component to display the current files
- */
- private static CyderScrollList cyderScrollList = new CyderScrollList(SCROLL_WIDTH, SCROLL_HEIGHT);
-
- /**
- * The x value of the directory scroll label and the loading files label.
- */
- private static final int directoryScrollX = 10;
-
- /**
- * The y value of the directory scroll label and the loading files label.
- */
- private static final int directoryScrollY = 90;
-
- /**
- * The loading files label.
- */
- private static final JLabel loadingFilesLabel = new JLabel();
-
- static {
- loadingFilesLabel.setText("Loading files...
");
- loadingFilesLabel.setHorizontalAlignment(JLabel.CENTER);
- loadingFilesLabel.setVerticalAlignment(JLabel.CENTER);
- loadingFilesLabel.setFont(CyderFonts.DEFAULT_FONT);
- loadingFilesLabel.setBorder(new LineBorder(CyderColors.navy, 5, false));
- loadingFilesLabel.setOpaque(false);
- loadingFilesLabel.setBounds(directoryScrollX, directoryScrollY, SCROLL_WIDTH, SCROLL_HEIGHT);
- }
-
- /**
- * The frame widget.
- */
- private static final int frameWidth = 630;
-
- /**
- * The frame height.
- */
- private static final int frameHeight = 510;
-
- /**
- * Thee length of the nav buttons.
- */
- private static final int navButtonLen = 40;
-
- /**
- * The y values of the nav buttons.
- */
- private static final int navButtonYOffset = 40;
-
- /**
- * The x value of the last nav button.
- */
- private static final int navButtonLastX = 10;
-
- /**
- * The padding between the nav buttons and the field.
- */
- private static final int fieldNavButtonPadding = 25;
-
- /**
- * The x value of the last nav button.
- */
- private static final int navButtonNextX = frameWidth - navButtonLastX - 2 * fieldNavButtonPadding;
-
- /**
- * Suppress default constructor.
- */
- private DirectoryViewer() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Widget(triggers = {"dir", "directory"}, description = "A directory navigator widget")
- public static void showGui() {
- showGui(new File(OsUtil.USER_DIR));
- }
-
- /**
- * Starts the directory viewer in the provided initial directory.
- *
- * @param initialDirectory the initial directory to start in
- * @return whether the gui was shown successfully
- */
- public static boolean showGui(File initialDirectory) {
- Preconditions.checkNotNull(initialDirectory);
- Preconditions.checkArgument(initialDirectory.exists());
-
- if (initialDirectory.isFile()) {
- initialDirectory = initialDirectory.getParentFile();
- }
-
- currentDirectory = initialDirectory;
-
- UiUtil.closeIfOpen(directoryFrame);
-
- directoryFrame = new CyderFrame.Builder()
- .setWidth(frameWidth)
- .setHeight(frameHeight)
- .setBackgroundIconFromColor(CyderColors.regularBackgroundColor)
- .build();
- directoryFrame.setTitle(getTitleForCurrentDirectory());
-
- directoryField = new CyderTextField();
- directoryField.setBackground(Color.white);
- directoryField.setForeground(CyderColors.navy);
- directoryField.setBorder(new LineBorder(CyderColors.navy, 5, false));
- directoryField.setText(currentDirectory.getAbsolutePath());
- directoryField.addActionListener(e -> {
- File chosenDir = new File(directoryField.getText());
-
- if (chosenDir.isDirectory()) {
- forward.clear();
- storeCurrentDirectory();
- currentDirectory = chosenDir;
- refreshFiles();
- } else if (chosenDir.isFile()) {
- FileUtil.openResource(chosenDir.getAbsolutePath(), true);
- }
- });
- directoryField.setBounds(60, 40, 500, 40);
- directoryFrame.getContentPane().add(directoryField);
-
- CyderButton last = new CyderButton(" < ");
- last.setFocusPainted(false);
- last.setForeground(CyderColors.navy);
- last.setBackground(CyderColors.regularRed);
- last.setFont(CyderFonts.SEGOE_20);
- last.setBorder(new LineBorder(CyderColors.navy, 5, false));
- last.addActionListener(e -> {
- if (!backward.isEmpty() && !backward.peek().equals(currentDirectory)) {
- forward.push(currentDirectory);
- currentDirectory = backward.pop();
- refreshFiles();
- }
- });
- last.setBounds(navButtonLastX, navButtonYOffset, navButtonLen, navButtonLen);
- directoryFrame.getContentPane().add(last);
-
- CyderButton next = new CyderButton(" > ");
- next.setFocusPainted(false);
- next.setForeground(CyderColors.navy);
- next.setBackground(CyderColors.regularRed);
- next.setFont(CyderFonts.SEGOE_20);
- next.setBorder(new LineBorder(CyderColors.navy, 5, false));
- next.addActionListener(e -> {
- if (!forward.isEmpty() && !forward.peek().equals(currentDirectory)) {
- backward.push(currentDirectory);
- storeCurrentDirectory();
- currentDirectory = forward.pop();
- refreshFiles();
- }
- });
- next.setBounds(navButtonNextX, navButtonYOffset, navButtonLen, navButtonLen);
- directoryFrame.getContentPane().add(next);
-
- loadingFilesLabel.setVisible(true);
- directoryFrame.getContentPane().add(loadingFilesLabel);
-
- directoryFrame.finalizeAndShow();
- directoryField.requestFocus();
-
- refreshFiles();
-
- return true;
- }
-
- /**
- * Stores the current directory as a previous location if necessary.
- */
- private static void storeCurrentDirectory() {
- if (backward.isEmpty()) {
- backward.push(currentDirectory);
- } else {
- File backwardFile = backward.peek();
- if (backwardFile != null && !backwardFile.getAbsolutePath().equals(currentDirectory.getAbsolutePath())) {
- backward.push(currentDirectory);
- }
- }
- }
-
- /**
- * Refreshes the files scroll list based on the current directory.
- */
- private static void refreshFiles() {
- loadingFilesLabel.setVisible(true);
-
- cyderScrollList.removeAllElements();
- directoryFrame.remove(dirScrollLabel);
-
- currentFiles.clear();
-
- File[] localDirectoryFiles = currentDirectory.listFiles();
- if (localDirectoryFiles != null && localDirectoryFiles.length > 0) {
- Collections.addAll(currentFiles, localDirectoryFiles);
- }
-
- cyderScrollList = new CyderScrollList(SCROLL_WIDTH, SCROLL_HEIGHT, CyderScrollList.SelectionPolicy.SINGLE);
- cyderScrollList.setScrollFont(CyderFonts.SEGOE_20.deriveFont(16f));
-
- currentFiles.forEach(file ->
- cyderScrollList.addElementWithDoubleClickAction(file.getName(), () -> {
- if (file.isDirectory()) {
- forward.clear();
- storeCurrentDirectory();
- currentDirectory = file;
- refreshFiles();
- } else {
- FileUtil.openResource(file.getAbsolutePath(), true);
- }
- }));
-
- dirScrollLabel = cyderScrollList.generateScrollList();
- dirScrollLabel.setBounds(directoryScrollX, directoryScrollY, SCROLL_WIDTH, SCROLL_HEIGHT);
- directoryFrame.getContentPane().add(dirScrollLabel);
-
- loadingFilesLabel.setVisible(false);
-
- directoryFrame.revalidate();
- directoryFrame.repaint();
-
- directoryFrame.setTitle(getTitleForCurrentDirectory());
- directoryField.setText(currentDirectory.getAbsolutePath());
- }
-
- private static String getTitleForCurrentDirectory() {
- String name = currentDirectory.getName();
- return name.isEmpty() ? currentDirectory.getAbsolutePath() : StringUtil.capsFirstWords(name.toLowerCase());
- }
-}
diff --git a/src/main/java/cyder/handlers/external/ImageViewer.java b/src/main/java/cyder/handlers/external/ImageViewer.java
deleted file mode 100644
index 0462045cb..000000000
--- a/src/main/java/cyder/handlers/external/ImageViewer.java
+++ /dev/null
@@ -1,395 +0,0 @@
-package cyder.handlers.external;
-
-import com.google.common.base.Preconditions;
-import cyder.console.Console;
-import cyder.files.DirectoryWatcher;
-import cyder.files.FileUtil;
-import cyder.files.WatchDirectoryEvent;
-import cyder.files.WatchDirectorySubscriber;
-import cyder.getter.GetInputBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.threads.CyderThreadFactory;
-import cyder.threads.CyderThreadRunner;
-import cyder.ui.drag.button.LeftButton;
-import cyder.ui.drag.button.RightButton;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.TitlePosition;
-import cyder.user.UserDataManager;
-import cyder.utils.ArrayUtil;
-import cyder.utils.ImageUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.IntStream;
-
-import static cyder.strings.CyderStrings.*;
-
-/**
- * A widget which displays the images supported by Cyder in a provided directory.
- */
-public class ImageViewer {
- /**
- * The next keyword.
- */
- private static final String NEXT = "Next";
-
- /**
- * The last keyword.
- */
- private static final String LAST = "Last";
-
- /**
- * The rename keyword.
- */
- private static final String RENAME = "Rename";
-
- /**
- * The maximum length of the image viewer frame.
- */
- private static final int maxFrameLength = 800;
-
- /**
- * The maximum dimension of the image viewer frame.
- */
- private static final Dimension maxFrameSize = new Dimension(maxFrameLength, maxFrameLength);
-
- /**
- * The getter util instance used to acquire the new filename from the user during a rename image attempt.
- */
- private final GetterUtil getterUtil = GetterUtil.getInstance();
-
- /**
- * The list of valid image files in the current directory, not recursive.
- */
- private final ArrayList validDirectoryImages = new ArrayList<>();
-
- /**
- * The watcher for the image directory.
- */
- private final DirectoryWatcher imageDirectoryWatcher;
-
- /**
- * The starting directory/file.
- */
- private final File imageDirectory;
-
- /**
- * The current index of the valid directory images list.
- */
- private int currentIndex;
-
- /**
- * The image frame.
- */
- private CyderFrame pictureFrame;
-
- /**
- * The next image button.
- */
- private RightButton nextButton;
-
- /**
- * The last image button.
- */
- private LeftButton lastButton;
-
- /**
- * Creates and returns a new instance.
- *
- * @param imageDirectoryOrFile the image directory or an image file.
- * If a file is provided, the file's parent is used as the directory
- * @return a new instance
- */
- public static ImageViewer getInstance(File imageDirectoryOrFile) {
- return new ImageViewer(imageDirectoryOrFile);
- }
-
- /**
- * Creates and returns a new instance.
- *
- * @param imageDirectoryOrFile the image directory or an image file.
- * If a file is provided, the file's parent is used as the directory
- * @throws NullPointerException if the provided file is null
- * @throws IllegalArgumentException if the provided file does not exist
- */
- private ImageViewer(File imageDirectoryOrFile) {
- Preconditions.checkNotNull(imageDirectoryOrFile);
- Preconditions.checkArgument(imageDirectoryOrFile.exists());
-
- this.imageDirectory = imageDirectoryOrFile;
-
- File watchDirectory = imageDirectoryOrFile.isFile()
- ? imageDirectoryOrFile.getParentFile() : imageDirectoryOrFile;
- this.imageDirectoryWatcher = new DirectoryWatcher(watchDirectory);
-
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * Shows this ImageViewer instance.
- *
- * @return whether the the image was successfully loaded and opened
- */
- public Future showGui() {
- return Executors.newSingleThreadExecutor(generateThreadFactory()).submit(() -> {
- refreshImageFiles();
-
- File currentImage = getCurrentImageFile();
-
- ImageIcon newImage = scaleImageIfNeeded(currentImage);
- pictureFrame = new CyderFrame.Builder()
- .setWidth(newImage.getIconWidth())
- .setHeight(newImage.getIconHeight())
- .setBackgroundIcon(newImage)
- .setBackgroundColor(Color.BLACK)
- .build();
- pictureFrame.setTitlePosition(TitlePosition.CENTER);
- revalidateTitle(FileUtil.getFilename(currentImage.getName()));
- pictureFrame.setVisible(true);
- pictureFrame.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- imageDirectoryWatcher.stopWatching();
- }
- });
-
- pictureFrame.setMenuButtonShown(true);
- pictureFrame.addMenuItem(RENAME, this::onRenameButtonClicked);
-
- nextButton = new RightButton();
- nextButton.setToolTipText(NEXT);
- nextButton.setClickAction(this::transitionForward);
- pictureFrame.getTopDragLabel().addRightButton(nextButton, 0);
-
- lastButton = new LeftButton();
- lastButton.setToolTipText(LAST);
- lastButton.setClickAction(this::transitionBackward);
- pictureFrame.getTopDragLabel().addRightButton(lastButton, 0);
-
- revalidateNavigationButtonVisibility();
- startDirectoryWatcher();
-
- pictureFrame.finalizeAndShow();
-
- return true;
- });
- }
-
- /**
- * Returns a reference to the current image file if possible. The first image is returned otherwise.
- *
- * @return a reference to the current image file. The first image is returned otherwise
- */
- private File getCurrentImageFile() {
- AtomicReference currentImage = new AtomicReference<>(validDirectoryImages.get(0));
- if (imageDirectory.isFile()) {
- validDirectoryImages.stream()
- .filter(image -> image.equals(imageDirectory))
- .findFirst().ifPresent(currentImage::set);
- }
- return currentImage.get();
- }
-
- /**
- * Generates and returns a new {@link CyderThreadFactory} for the loading {@link Executor}.
- *
- * @return a new {@link CyderThreadFactory} for the loading {@link Executor}
- */
- private CyderThreadFactory generateThreadFactory() {
- return new CyderThreadFactory("ImageViewer showGui thread, directory" + colon + space + imageDirectory);
- }
-
- /**
- * Refreshes the {@link #validDirectoryImages} list based on the currently set {@link #imageDirectory}.
- */
- private void refreshImageFiles() {
- validDirectoryImages.clear();
-
- File[] neighbors = imageDirectory.isDirectory()
- ? imageDirectory.listFiles()
- : imageDirectory.getParentFile().listFiles();
- if (ArrayUtil.nullOrEmpty(neighbors)) return;
- Arrays.stream(neighbors).filter(FileUtil::isSupportedImageExtension).forEach(validDirectoryImages::add);
- }
-
- /**
- * Transitions to the next image if possible.
- */
- private void transitionForward() {
- refreshImageFiles();
- if (validDirectoryImages.size() < 2) return;
- currentIndex = currentIndex == validDirectoryImages.size() - 1 ? 0 : currentIndex + 1;
- revalidateFromTransition();
- }
-
- /**
- * Transitions to the previous image if possible.
- */
- private void transitionBackward() {
- refreshImageFiles();
- if (validDirectoryImages.size() < 2) return;
- currentIndex = currentIndex == 0 ? validDirectoryImages.size() - 1 : currentIndex - 1;
- revalidateFromTransition();
- }
-
- /**
- * The logic to perform following a transition.
- */
- private void revalidateFromTransition() {
- Point oldCenterPoint = pictureFrame.getCenterPointOnScreen();
- ImageIcon image = scaleImageIfNeeded(validDirectoryImages.get(currentIndex));
- pictureFrame.setSize(image.getIconWidth(), image.getIconHeight());
- pictureFrame.setBackground(image);
- pictureFrame.setCenterPoint(oldCenterPoint);
- pictureFrame.refreshBackground();
- revalidateTitle(FileUtil.getFilename(validDirectoryImages.get(currentIndex).getName()));
- }
-
- /**
- * Returns a scaled image icon for the provided image
- * file if the image is bigger than MAX_LEN x MAX_LEN.
- *
- * @param imageFile the image file to process
- * @return the ImageIcon from the image file guaranteed to be no bigger than MAX_LEN x MAX_LEN
- */
- private ImageIcon scaleImageIfNeeded(File imageFile) {
- Preconditions.checkNotNull(imageFile);
- Preconditions.checkArgument(imageFile.exists());
- Preconditions.checkArgument(imageFile.isFile());
-
- try {
- BufferedImage bufferedImage = ImageUtil.read(imageFile);
- bufferedImage = ImageUtil.ensureFitsInBounds(bufferedImage, maxFrameSize);
- return ImageUtil.toImageIcon(bufferedImage);
- } catch (Exception e) {
- throw new IllegalStateException("Could not generate ImageIcon for file" + colon
- + space + imageFile.getAbsolutePath() + ", error: " + e.getMessage());
- }
- }
-
- /**
- * The actions to invoke when the rename menu item is pressed.
- */
- private void onRenameButtonClicked() {
- File currentRename = new File(validDirectoryImages.get(currentIndex).getAbsolutePath());
- File currentBackground = Console.INSTANCE
- .getCurrentBackground().getReferenceFile().getAbsoluteFile();
-
- if (currentRename.getAbsolutePath().equals(currentBackground.getAbsolutePath())) {
- pictureFrame.notify("Sorry, " + UserDataManager.INSTANCE.getUsername()
- + ", but you're not allowed to rename the background you are currently using");
- return;
- }
-
- getterUtil.closeAllGetInputFrames();
-
- String initialFieldText = FileUtil.getFilename(validDirectoryImages.get(currentIndex));
-
- CyderThreadRunner.submit(() -> {
- try {
- GetInputBuilder builder = new GetInputBuilder(RENAME, "New filename for"
- + space + quote + validDirectoryImages.get(currentIndex).getName() + quote)
- .setRelativeTo(pictureFrame)
- .setInitialFieldText(initialFieldText)
- .setSubmitButtonText(RENAME);
- Optional optionalName = getterUtil.getInput(builder);
- if (optionalName.isEmpty() || optionalName.get().equals(initialFieldText)) return;
-
- String requestedName = optionalName.get();
-
- File oldFileReference = new File(validDirectoryImages.get(currentIndex).getAbsolutePath());
- File newFileReference = new File(oldFileReference.getAbsolutePath()
- .replace(FileUtil.getFilename(oldFileReference), requestedName));
-
- if (oldFileReference.renameTo(newFileReference)) {
- pictureFrame.notify("Successfully renamed to" + space + quote + requestedName + quote);
-
- refreshImageFiles();
- IntStream.range(0, validDirectoryImages.size())
- .forEach(index -> {
- if (FileUtil.getFilename(validDirectoryImages.get(index)).equals(requestedName)) {
- currentIndex = index;
- }
- });
- revalidateTitle(requestedName);
- } else {
- pictureFrame.notify("Could not rename at this time");
- }
-
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, "ImageViewer File Renamer, file" + colon + space + initialFieldText);
- }
-
- /**
- * Revalidates the frame title based on the provided name.
- *
- * @param title the title of the frame
- */
- public void revalidateTitle(String title) {
- Preconditions.checkNotNull(title);
-
- title = title.trim();
-
- try {
- BufferedImage image = ImageUtil.read(validDirectoryImages.get(currentIndex));
- int width = image.getWidth();
- int height = image.getHeight();
- pictureFrame.setTitle(title + space + openingBracket + width + "x" + height + closingBracket);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- pictureFrame.setTitle(title);
- }
- }
-
- /**
- * Starts the directory watcher to update the visibilities of the
- * next and last buttons based on the contents of the image directory.
- */
- private void startDirectoryWatcher() {
- WatchDirectorySubscriber subscriber = new WatchDirectorySubscriber() {
- @Override
- public void onEvent(DirectoryWatcher broker, WatchDirectoryEvent event, File eventFile) {
- refreshImageFiles();
- revalidateNavigationButtonVisibility();
- }
- };
- subscriber.subscribeTo(WatchDirectoryEvent.FILE_ADDED,
- WatchDirectoryEvent.FILE_DELETED, WatchDirectoryEvent.FILE_MODIFIED);
- imageDirectoryWatcher.addSubscriber(subscriber);
- imageDirectoryWatcher.startWatching();
- }
-
- /**
- * Revalidates the visibility of the navigation buttons.
- */
- private void revalidateNavigationButtonVisibility() {
- refreshImageFiles();
- setNavigationButtonsVisibility(validDirectoryImages.size() > 1);
- }
-
- /**
- * Sets the visibility of the navigation buttons.
- *
- * @param visible the visibility of the navigation buttons
- */
- private void setNavigationButtonsVisibility(boolean visible) {
- nextButton.setVisible(visible);
- lastButton.setVisible(visible);
- }
-}
diff --git a/src/main/java/cyder/handlers/external/TextViewer.java b/src/main/java/cyder/handlers/external/TextViewer.java
deleted file mode 100644
index 030cc0e6d..000000000
--- a/src/main/java/cyder/handlers/external/TextViewer.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package cyder.handlers.external;
-
-import com.google.common.base.Preconditions;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.enumerations.Extension;
-import cyder.files.FileUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.strings.CyderStrings;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderCaret;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.pane.CyderScrollPane;
-import cyder.utils.OsUtil;
-
-import javax.swing.*;
-import javax.swing.border.Border;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-
-/**
- * A handler for viewing text files.
- */
-public class TextViewer {
- /**
- * The file currently being displayed.
- */
- private File file;
-
- /**
- * The default frame width.
- */
- private static final int defaultFrameWidth = 600;
-
- /**
- * The default frame height.
- */
- private static final int defaultFrameHeight = 680;
-
- /**
- * The font for the name field.
- */
- private static final Font nameFieldFont = new Font("Agency FB", Font.BOLD, 26);
-
- /**
- * The border for the name field.
- */
- private static final Border nameFieldBorder
- = BorderFactory.createMatteBorder(0, 0, 4, 0, CyderColors.navy);
-
- /**
- * The padding between the frame and the contents scrolls.
- */
- private static final int scrollPadding = 25;
-
- /**
- * The length of the scroll.
- */
- private static final int scrollLength = defaultFrameWidth - 2 * scrollPadding;
-
- /**
- * The height of the scroll.
- */
- private static final int scrollHeight = scrollLength - 50;
-
- /**
- * The save button text.
- */
- private static final String SAVE = "Save";
-
- /**
- * The file contents area.
- */
- private static JTextPane contentsArea;
-
- /**
- * The file name field.
- */
- private static CyderTextField nameField;
-
- /**
- * The frame for this text editor.
- */
- private CyderFrame textFrame;
-
- /**
- * Returns a new text viewer instance to view the provided file.
- *
- * @param file the file to view
- * @return a text viewer instance
- */
- public static TextViewer getInstance(File file) {
- return new TextViewer(file);
- }
-
- /**
- * Constructs a new text viewer with the provided file.
- *
- * @param file the file to display for the text file
- */
- private TextViewer(File file) {
- this.file = Preconditions.checkNotNull(file);
- }
-
- /**
- * Opens the text viewer gui.
- *
- * @return whether the gui opened successfully
- */
- @CanIgnoreReturnValue
- public boolean showGui() {
- textFrame = new CyderFrame.Builder()
- .setWidth(defaultFrameWidth)
- .setHeight(defaultFrameHeight)
- .build();
-
- nameField = new CyderTextField();
- nameField.setFont(nameFieldFont);
- nameField.setForeground(CyderColors.navy);
- nameField.setCaret(new CyderCaret(CyderColors.navy));
- nameField.setBackground(CyderColors.vanilla);
- nameField.setSize(300, 40);
- nameField.setToolTipText("Filename");
- nameField.setBorder(nameFieldBorder);
- nameField.setText(FileUtil.getFilename(file));
-
- contentsArea = new JTextPane();
- contentsArea.setText(getCurrentFileContents());
- contentsArea.setSize(scrollLength, scrollHeight);
- contentsArea.setBackground(CyderColors.vanilla);
- contentsArea.setBorder(new LineBorder(CyderColors.navy, 5));
- contentsArea.setFocusable(true);
- contentsArea.setEditable(true);
- contentsArea.setSelectionColor(CyderColors.selectionColor);
- contentsArea.setFont(Console.INSTANCE.generateUserFont());
- contentsArea.setForeground(CyderColors.navy);
- contentsArea.setCaret(new CyderCaret(CyderColors.navy));
- contentsArea.setCaretColor(contentsArea.getForeground());
-
- CyderScrollPane contentsScroll = new CyderScrollPane(contentsArea,
- ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
- contentsScroll.setThumbColor(CyderColors.regularPink);
- contentsScroll.setSize(scrollLength, scrollHeight);
- contentsScroll.getViewport().setOpaque(false);
- contentsScroll.setOpaque(false);
- contentsScroll.setBorder(null);
- contentsArea.setAutoscrolls(true);
-
- CyderButton saveButton = new CyderButton(SAVE);
- saveButton.setSize(new Dimension(contentsScroll.getWidth(), 40));
- saveButton.addActionListener(e -> saveButtonAction());
-
- CyderPartitionedLayout textLayout = new CyderPartitionedLayout();
- textLayout.spacer(2);
- textLayout.addComponentMaintainSize(nameField);
- textLayout.spacer(2);
- textLayout.addComponentMaintainSize(contentsScroll);
- textLayout.spacer(2);
- textLayout.addComponentMaintainSize(saveButton);
- textLayout.spacer(2);
-
- revalidateTitle();
- textFrame.setCyderLayout(textLayout);
- textFrame.finalizeAndShow();
-
- return true;
- }
-
- /**
- * Reads and returns the contents of the file.
- *
- * @return the contents of the file
- */
- private String getCurrentFileContents() {
- try {
- byte[] encoded = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
- return new String(encoded, StandardCharsets.UTF_8);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- throw new IllegalStateException("Could not read contents of current note file");
- }
-
- /**
- * The actions to invoke when the save button is pressed.
- */
- private void saveButtonAction() {
- String nameContents = nameField.getTrimmedText();
- if (nameContents.toLowerCase().endsWith(Extension.TXT.getExtension())) {
- nameContents = nameContents.substring(0, nameContents.length() - Extension.TXT.getExtension().length());
- }
-
- String requestedName = nameContents + Extension.TXT.getExtension();
-
- if (!FileUtil.isValidFilename(requestedName)) {
- textFrame.notify("Invalid filename");
- return;
- }
-
- File parent = file.getParentFile();
- File createFile = OsUtil.buildFile(parent.getAbsolutePath(), requestedName);
- if (!OsUtil.createFile(createFile, true)) {
- textFrame.notify("Could not create file: \"" + requestedName + CyderStrings.quote);
- }
- if (!OsUtil.deleteFile(file)) {
- textFrame.notify("Could not update contents of file");
- }
-
- file = createFile;
-
- String contents = contentsArea.getText();
- try (BufferedWriter write = new BufferedWriter(new FileWriter(file))) {
- write.write(contents);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- textFrame.notify("Saved file and contents under: \"" + requestedName + CyderStrings.quote);
- }
-
- /**
- * Revalidates the title of the frame.
- */
- private void revalidateTitle() {
- textFrame.setTitle(FileUtil.getFilename(file));
- }
-
- /**
- * Saves the contents to the file.
- *
- * @param contents the contents to save.
- */
- private void saveContentsToFile(String contents) {
- Preconditions.checkNotNull(contents);
-
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
- writer.write(contents);
- } catch (Exception exception) {
- ExceptionHandler.handle(exception);
- }
- }
-}
diff --git a/src/main/java/cyder/handlers/external/package-info.java b/src/main/java/cyder/handlers/external/package-info.java
deleted file mode 100644
index 092939d38..000000000
--- a/src/main/java/cyder/handlers/external/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Handlers related to how files are opened if there is a custom implemented viewer.
- */
-package cyder.handlers.external;
diff --git a/src/main/java/cyder/handlers/input/BaseInputHandler.java b/src/main/java/cyder/handlers/input/BaseInputHandler.java
deleted file mode 100644
index 9c2fbdc33..000000000
--- a/src/main/java/cyder/handlers/input/BaseInputHandler.java
+++ /dev/null
@@ -1,1407 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.reflect.ClassPath;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Handle;
-import cyder.annotations.Widget;
-import cyder.audio.GeneralAudioPlayer;
-import cyder.console.Console;
-import cyder.constants.CyderRegexPatterns;
-import cyder.enumerations.Dynamic;
-import cyder.exceptions.FatalException;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.props.Props;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.*;
-import cyder.ui.pane.CyderOutputPane;
-import cyder.user.UserDataManager;
-import cyder.user.UserFile;
-import cyder.utils.OsUtil;
-import cyder.utils.ReflectionUtil;
-import cyder.utils.SecurityUtil;
-import cyder.utils.StaticUtil;
-import cyder.youtube.YouTubeDownloadManager;
-import org.apache.commons.text.similarity.JaroWinklerDistance;
-
-import javax.swing.*;
-import javax.swing.text.ElementIterator;
-import javax.swing.text.Style;
-import javax.swing.text.StyleConstants;
-import javax.swing.text.StyledDocument;
-import java.io.*;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * The base input handler used for linked JTextPane printing
- * operations and raw user input sub-handler triggering.
- */
-@SuppressWarnings("SpellCheckingInspection") /* Cyder specific words */
-public class BaseInputHandler {
- /**
- * The linked CyderOutputPane.
- */
- private final CyderOutputPane linkedOutputPane;
-
- /**
- * boolean describing whether to quickly append all remaining queued objects to the linked JTextPane.
- */
- private boolean shouldFinishPrinting;
-
- /**
- * The file to redirect the outputs of a command to if redirection is enabled.
- */
- private File redirectionFile;
-
- /**
- * Boolean describing whether possible command output should be redirected to the redirectionFile.
- */
- private boolean redirection;
-
- /**
- * The command that is being handled.
- */
- private String command;
-
- /**
- * The arguments of the command.
- */
- private final ArrayList args = new ArrayList<>();
-
- /**
- * The handles which contain specific triggers for pre-determined commands.
- */
- public static final ImmutableList> primaryHandlers = ImmutableList.of(
- PixelationHandler.class,
- GitHandler.class,
- ImageHandler.class,
- PlayAudioHandler.class,
- ColorHandler.class,
- NetworkHandler.class,
- StatHandler.class,
- NumberHandler.class,
- ThreadHandler.class,
- UiHandler.class,
- FileHandler.class,
- FrameMovementHandler.class,
- PropHandler.class
- );
-
- /**
- * The handles which have do not have specific triggers
- * and instead perform checks and operations on the raw command.
- */
- public static final ImmutableList> finalHandlers = ImmutableList.of(
- GeneralPrintHandler.class,
- WidgetHandler.class,
- MathHandler.class,
- UrlHandler.class,
- UserDataHandler.class,
- GuiTestHandler.class,
- TestHandler.class,
- WrappedCommandHandler.class
- );
-
- /**
- * Suppress default constructor.
- */
- private BaseInputHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * Constructs a new base input handler liked to the provided {@link JTextPane}.
- *
- * @param outputArea the JTextPane object to append content to
- */
- public BaseInputHandler(JTextPane outputArea) {
- Preconditions.checkNotNull(outputArea);
-
- this.linkedOutputPane = new CyderOutputPane(outputArea);
- initializeSpecialThreads();
- clearLists();
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * Releases resources acquired and initialized via the constructor.
- */
- public void deactivate() {
- deactivateSpecialThreads();
- killThreads();
- }
-
- /**
- * Sets up the custom thread objects to be managed by this {@link BaseInputHandler}, that of the following:
- *
- * {@link YoutubeUuidCheckerManager}
- * {@link BletchyAnimationManager}
- *
- */
- private void initializeSpecialThreads() {
- YoutubeUuidCheckerManager.INSTANCE.initialize(linkedOutputPane);
- BletchyAnimationManager.INSTANCE.initialize(linkedOutputPane);
- }
-
- /**
- * Releases the resources initialied by the {@link #initializeSpecialThreads()} method.
- */
- private void deactivateSpecialThreads() {
- YoutubeUuidCheckerManager.INSTANCE.deactivate();
- BletchyAnimationManager.INSTANCE.deactivate();
- }
-
- /**
- * Clears the console printing lists.
- */
- private void clearLists() {
- consolePrintingList.clear();
- consolePriorityPrintingList.clear();
- }
-
- /**
- * The input type associated with possible handle strings.
- */
- private enum InputType {
- /**
- * The input was user generated.
- */
- USER,
-
- /**
- * The input is the result of a similar command invocation.
- */
- SIMILAR_COMMAND
- }
-
- /**
- * Handles the input and provides output if necessary to the linked JTextPane.
- *
- * @param op the operation that is being handled
- */
- public void handle(String op) {
- handle(op, InputType.USER);
- }
-
- /**
- * Handles the input and provides output if necessary to the linked JTextPane.
- *
- * @param op the operation that is being handled
- * @param inputType the input type
- */
- public final void handle(String op, InputType inputType) {
- if (!handlePreliminaries(op, inputType)) return;
- if (attemptRedirection()) return;
- if (attemptPrimaryHandlers()) return;
- if (attemptFinalHandlers()) return;
-
- unknownInput();
- }
-
- /**
- * Attempts to pass the current command input to the {@link #redirectionHandler} if not null.
- *
- * @return whether the {@link #redirectionHandler} handled the current command input
- */
- private boolean attemptRedirection() {
- if (redirectionHandler != null) {
- for (Method method : redirectionHandler.getMethods()) {
- if (method.isAnnotationPresent(Handle.class)) {
- if (method.getParameterCount() != 0) continue;
-
- Object invocationResult;
- try {
- invocationResult = method.invoke(redirectionHandler);
- } catch (Exception e) {
- throw new FatalException(e.getMessage());
- }
-
- if (invocationResult instanceof Boolean bool && bool) return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Attempts to handle the current command input using the {@link #primaryHandlers}.
- *
- * @return whether a primary handler handled the current command input
- */
- private boolean attemptPrimaryHandlers() {
- for (Class> handle : primaryHandlers) {
- for (Method method : handle.getMethods()) {
- if (method.isAnnotationPresent(Handle.class)) {
- if (method.getParameterCount() != 0) continue;
-
- String[] triggers = method.getAnnotation(Handle.class).value();
- for (String trigger : triggers) {
- if (commandAndArgsToString().startsWith(trigger)) {
- Object invocationResult;
- try {
- invocationResult = method.invoke(handle);
- } catch (Exception e) {
- throw new FatalException(e.getMessage());
- }
-
- if (invocationResult instanceof Boolean bool && bool) return true;
- }
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Attempts to handle the current command input using the {@link #finalHandlers}.
- *
- * @return whether a final handler handled the current command input
- */
- private boolean attemptFinalHandlers() {
- for (Class> handle : finalHandlers) {
- for (Method method : handle.getMethods()) {
- if (method.isAnnotationPresent(Handle.class)) {
- if (method.getParameterCount() != 0) continue;
-
- Object invocationResult;
- try {
- invocationResult = method.invoke(handle);
- } catch (Exception e) {
- throw new FatalException(e.getMessage());
- }
-
- if (invocationResult instanceof Boolean bool && bool) return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Handles preliminaries such as argument/command parsing and redirection checks
- * before passing input data to the handle methods.
- *
- * @param command the command to handle preliminaries on before behind handled
- * @param inputType the input type
- * @return whether preliminary checks successfully completed
- */
- private boolean handlePreliminaries(String command, InputType inputType) {
- Preconditions.checkNotNull(linkedOutputPane);
- Preconditions.checkNotNull(command);
- this.command = command.trim();
-
- resetMembers();
-
- if (StringUtil.isNullOrEmpty(this.command)) {
- Logger.log(LogTag.HANDLE_METHOD, "Failed preliminaries for empty/null operation");
- return false;
- }
-
- String commandAndArgsToString = commandAndArgsToString();
- Logger.log(LogTag.CLIENT, (inputType == InputType.SIMILAR_COMMAND
- ? "" : "[Similar Command]: ") + commandAndArgsToString);
-
- if (UserDataManager.INSTANCE.shouldFilterchat()) {
- StringUtil.BlockedWordResult result = checkFoulLanguage();
- if (result.failed()) {
- println("Sorry, " + UserDataManager.INSTANCE.getUsername() + ", but that language"
- + " is prohibited, word: " + CyderStrings.quote + result.triggerWord() + CyderStrings.quote);
- Logger.log(LogTag.HANDLE_METHOD, "Failed preliminaries due to prohibited language");
- return false;
- }
- }
-
- parseArgsFromCommand();
- redirectionCheck();
-
- return true;
- }
-
- /**
- * Parses the current command into arguments and a command.
- */
- private void parseArgsFromCommand() {
- String[] parts = this.command.split(CyderRegexPatterns.whiteSpaceRegex);
- this.command = parts[0];
- if (parts.length > 1) {
- args.clear();
- args.addAll(Arrays.asList(parts).subList(1, parts.length));
- }
- }
-
- /**
- * Checks for whether the provided string contains blocked words.
- *
- * @return the blocked word if found
- */
- private StringUtil.BlockedWordResult checkFoulLanguage() {
- return StringUtil.containsBlockedWords(command, true);
- }
-
- /**
- * Resets redirection, the redirection file, and the arguments array.
- */
- private void resetMembers() {
- redirection = false;
- redirectionFile = null;
- args.clear();
- }
-
- /**
- * The char for redirecting input to a file.
- */
- private static final String REDIRECTION_CHAR = ">";
-
- /**
- * Checks for a requested redirection and attempts to create the file if valid.
- */
- private void redirectionCheck() {
- if (args.size() < 2) return;
- String secondToLastArg = args.get(args.size() - 2);
- if (!secondToLastArg.equalsIgnoreCase(REDIRECTION_CHAR)) return;
-
- String requestedFilename = args.get(args.size() - 1);
-
- if (!FileUtil.isValidFilename(requestedFilename)) {
- onFailedRedirect("Provided filename is not valid: \"" + requestedFilename + "\"");
- return;
- }
-
- redirection = true;
-
- try {
- redirectionLock.acquire();
-
- redirectionFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.FILES.getName(), requestedFilename).getAbsoluteFile();
-
- if (redirectionFile.exists()) {
- OsUtil.deleteFile(redirectionFile);
- }
-
- if (!OsUtil.createFile(redirectionFile, true)) {
- onFailedRedirect("Could not create redirection file: " + redirectionFile.getAbsolutePath());
- }
- } catch (Exception e) {
- onFailedRedirect(e.getMessage());
- } finally {
- redirectionLock.release();
- }
- }
-
- /**
- * Handles a failed redirection attempt.
- *
- * @param errorMessage the error message to show to the user
- */
- private void onFailedRedirect(String errorMessage) {
- redirection = false;
- redirectionFile = null;
-
- println("Failed to redirect output: " + errorMessage);
- }
-
- /**
- * The final handle method for if all other handle methods failed.
- */
- private void unknownInput() {
- SimilarCommand similarCommandObj = getSimilarCommand(command);
- boolean wrapShell = UserDataManager.INSTANCE.shouldWrapShell();
-
- if (similarCommandObj.command().isPresent()) {
- String similarCommand = similarCommandObj.command().get();
- double tolerance = similarCommandObj.tolerance();
- if (tolerance == 1.0) return;
-
- if (!StringUtil.isNullOrEmpty(similarCommand)) {
- Logger.log(LogTag.DEBUG, "Similar command to " + CyderStrings.quote
- + command + CyderStrings.quote + " found with tolerance of " + tolerance
- + ", command: " + CyderStrings.quote + similarCommand + CyderStrings.quote);
-
- if (!wrapShell) {
- boolean autoTrigger = Props.autoTriggerSimilarCommands.getValue();
- boolean toleranceMet = tolerance >= Props.autoTriggerSimilarCommandTolerance.getValue();
-
- // User may want to change configuration value if they're more error prone
- if (tolerance >= Props.similarCommandTolerance.getValue()) {
- if (autoTrigger && toleranceMet) {
- println(UNKNOWN_COMMAND + "; Invoking similar command: "
- + CyderStrings.quote + similarCommand + CyderStrings.quote);
- handle(similarCommand, InputType.SIMILAR_COMMAND);
- } else {
- println(UNKNOWN_COMMAND + "; Most similar command: "
- + CyderStrings.quote + similarCommand + CyderStrings.quote);
- }
-
- return;
- }
- }
- }
- }
-
- if (wrapShell) {
- CyderThreadRunner.submit(this::performWrapShell, "Unknown Input Shell Wrapper, input: "
- + StringUtil.joinParts(args, CyderStrings.space));
-
- } else {
- println(UNKNOWN_COMMAND);
- }
- }
-
- /**
- * A record representing a found similar command how close the
- * found command is to the original string.
- */
- private record SimilarCommand(Optional command, double tolerance) {}
-
- /**
- * Finds the most similar command to the unrecognized one provided.
- *
- * @param command the user entered command to attempt to find a similar command to
- * @return the most similar command to the one provided
- */
- private static SimilarCommand getSimilarCommand(String command) {
- Preconditions.checkNotNull(command);
- Preconditions.checkArgument(!command.isEmpty());
-
- String mostSimilarTrigger = "";
- float mostSimilarRatio = 0.0f;
-
- for (ClassPath.ClassInfo classInfo : ReflectionUtil.getCyderClasses()) {
- Class> clazz = classInfo.load();
-
- for (Method m : clazz.getMethods()) {
- ImmutableList triggers = ImmutableList.of();
-
- if (m.isAnnotationPresent(Handle.class)) {
- triggers = ImmutableList.copyOf(m.getAnnotation(Handle.class).value());
- } else if (m.isAnnotationPresent(Widget.class)) {
- triggers = ImmutableList.copyOf(m.getAnnotation(Widget.class).triggers());
- }
-
- for (String trigger : triggers) {
- double ratio = new JaroWinklerDistance().apply(trigger, command);
-
- if (ratio > mostSimilarRatio) {
- mostSimilarRatio = (float) ratio;
- mostSimilarTrigger = trigger;
- }
- }
- }
- }
-
- return new SimilarCommand(StringUtil.isNullOrEmpty(mostSimilarTrigger)
- ? Optional.empty()
- : Optional.of(mostSimilarTrigger), mostSimilarRatio);
- }
-
- /**
- * The actions performed when it is known that a wrap shell action should be taken.
- */
- private void performWrapShell() {
- println(UNKNOWN_COMMAND + ", passing to operating system native shell" + CyderStrings.space
- + CyderStrings.openingParenthesis + OsUtil.getShellName() + CyderStrings.closingParenthesis);
-
- CyderThreadRunner.submit(() -> {
- try {
- Process process = createAndStartWrapShellProcess();
-
- BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
- String line;
- process.waitFor();
-
- while ((line = reader.readLine()) != null) {
- println(line);
-
- if (escapeWrapShell) {
- process.destroy();
- break;
- }
- }
-
- escapeWrapShell = false;
- } catch (Exception ignored) {
- println(UNKNOWN_COMMAND);
- }
- }, WRAP_SHELL_THREAD_NAME);
- }
-
- /**
- * Creates and returns the process that invokes the command and args as an operating system command.
- *
- * @return the created process after starting
- * @throws IOException if any IO errors occur when starting the process
- */
- @ForReadability
- private Process createAndStartWrapShellProcess() throws IOException {
- ArrayList processArgs = new ArrayList<>(args);
- processArgs.add(0, command);
- ProcessBuilder builder = new ProcessBuilder(processArgs);
- builder.redirectErrorStream(true);
- return builder.start();
- }
-
- /**
- * Used to escape the terminal wrapper.
- */
- private boolean escapeWrapShell;
-
- /**
- * The name of the thread when wrapping the shell
- */
- private static final String WRAP_SHELL_THREAD_NAME = "Wrap Shell Thread";
-
- /**
- * The text to print for an unknown command.
- */
- private static final String UNKNOWN_COMMAND = "Unknown command";
-
- /**
- * Returns the output area's {@link JTextPane}.
- *
- * @return the output area's {@link JTextPane}
- */
- public final JTextPane getJTextPane() {
- return linkedOutputPane.getJTextPane();
- }
-
- /**
- * Ends any custom threads such as YouTube or bletchy
- * that may have been invoked via this input handler.
- */
- public final void killThreads() {
- YoutubeUuidCheckerManager.INSTANCE.killAll();
- BletchyAnimationManager.INSTANCE.kill();
- }
-
- /**
- * Semaphore for adding objects to both consolePrintingList and consolePriorityPrintingList.
- */
- private final Semaphore printingListAddLock = new Semaphore(1);
-
- /**
- * Acquires the printingListAddLock.
- * This method should only be called from inside one of the printing lists overriden add method.
- */
- @ForReadability
- private void lockAddingToLists() {
- try {
- printingListAddLock.acquire();
- } catch (Exception exception) {
- ExceptionHandler.handle(exception);
- }
- }
-
- /**
- * Releases the printingListAddLock.
- * This method should only be called from inside one of the printing lists overriden add method.
- */
- @ForReadability
- private void unlockAddingToLists() {
- printingListAddLock.release();
- }
-
- /**
- * The printing list for non-important outputs.
- * DO NOT ADD DIRECTLY TO THIS LIST UNLESS YOU ARE A PRINT METHOD.
- */
- private final ArrayList consolePrintingList = new ArrayList<>() {
- @Override
- public boolean add(Object e) {
- lockAddingToLists();
- boolean ret = super.add(e);
- startConsolePrintingAnimationIfNeeded();
- unlockAddingToLists();
- return ret;
- }
- };
-
- /*
- Note to maintainers: these lists are anonymously declared to allow for their add methods
- to have additional functionality such as thread-safety via printingListAddLock.
- */
-
- /**
- * The priority printing list for important outputs.
- * DO NOT ADD DIRECTLY TO THIS LIST UNLESS YOU ARE A PRINT METHOD.
- */
- private final ArrayList consolePriorityPrintingList = new ArrayList<>() {
- @Override
- public boolean add(Object e) {
- lockAddingToLists();
- boolean ret = super.add(e);
- startConsolePrintingAnimationIfNeeded();
- unlockAddingToLists();
- return ret;
- }
- };
-
- /**
- * Whether the printing animation thread is running
- */
- private boolean printingAnimationRunning;
-
- /**
- * Begins the typing animation for the Console if it has not already started.
- */
- private void startConsolePrintingAnimationIfNeeded() {
- if (printingAnimationRunning) return;
- printingAnimationRunning = true;
- CyderThreadRunner.submit(consolePrintingRunnable, IgnoreThread.ConsolePrintingAnimation.getName());
- }
-
- /**
- * Returns whether both the printing lists are empty.
- *
- * @return whether both the printing lists are empty
- */
- @ForReadability
- private boolean listsEmpty() {
- return consolePrintingList.isEmpty() && consolePriorityPrintingList.isEmpty();
- }
-
- /**
- * The delay between updating the value of typing animation from the current user's userdata.
- */
- private static final int USER_DATA_POLL_FREQUENCY_MS = 3000;
-
- /**
- * Returns whether the typing animation should be performed.
- *
- * @return whether the typing animation should be performed
- */
- @ForReadability
- private boolean shouldDoTypingAnimation() {
- return UserDataManager.INSTANCE.shouldShowTypingAnimation();
- }
-
- /**
- * Returns whether the typing animation sound should be played.
- *
- * @return whether the typing animation sound should be played
- */
- @ForReadability
- private boolean shouldDoTypingSound() {
- return UserDataManager.INSTANCE.shouldPlayTypingSound();
- }
-
- /**
- * The console printing animation runnable.
- */
- private final Runnable consolePrintingRunnable = () -> {
- try {
- boolean shouldDoTypingAnimation = shouldDoTypingAnimation();
- boolean shouldDoTypingSound = shouldDoTypingSound();
- long lastPollTime = System.currentTimeMillis();
- int lineTimeout = Props.printingAnimationLineTimeout.getValue();
-
- while (!Console.INSTANCE.isClosed() && !listsEmpty()) {
- if (System.currentTimeMillis() - lastPollTime > USER_DATA_POLL_FREQUENCY_MS) {
- lastPollTime = System.currentTimeMillis();
- shouldDoTypingAnimation = shouldDoTypingAnimation();
- shouldDoTypingSound = shouldDoTypingSound();
- }
-
- if (!consolePriorityPrintingList.isEmpty()) {
- Object line = removeAndLog(consolePriorityPrintingList);
-
- if (redirection) {
- redirectionWrite(line);
- } else {
- switch (line) {
- case JComponent jComponent -> insertJComponent(jComponent);
- case ImageIcon imageIcon -> insertImageIcon(imageIcon);
- case default -> insertAsString(line);
- }
- }
- } else if (!consolePrintingList.isEmpty()) {
- Object line = removeAndLog(consolePrintingList);
-
- if (redirection) {
- redirectionWrite(line);
- } else {
- switch (line) {
- case String string:
- if (shouldDoTypingAnimation) {
- if (shouldFinishPrinting) {
- insertAsString(string);
- } else {
- innerPrintString(string, shouldDoTypingSound);
- }
- } else {
- insertAsString(line);
- }
- break;
- case JComponent jComponent:
- insertJComponent(jComponent);
- break;
- case ImageIcon imageIcon:
- insertImageIcon(imageIcon);
- break;
- default:
- insertAsString(line);
- break;
- }
- }
- } else {
- shouldFinishPrinting = false;
- }
-
- if (!shouldFinishPrinting && shouldDoTypingAnimation) ThreadUtil.sleep(lineTimeout);
- }
-
- printingAnimationRunning = false;
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- };
-
- /**
- * Removes, logs, and returns the first element from the provided list.
- *
- * @param list the list to perform the operations on
- * @return the object removed from the list
- */
- private Object removeAndLog(ArrayList list) {
- Preconditions.checkNotNull(list);
- Preconditions.checkArgument(!list.isEmpty());
-
- Object ret = list.remove(0);
- Logger.log(LogTag.CONSOLE_OUT, ret);
- return ret;
- }
-
- // -----------------------
- // Document insert methods
- // -----------------------
-
- /**
- * Inserts the provided object into the current outputArea after
- * invoking {@link String#valueOf(Object))} on the provided object.
- *
- * @param object the object to insert
- */
- private void insertAsString(Object object) {
- Preconditions.checkNotNull(object);
-
- StyledDocument document = (StyledDocument) getJTextPane().getDocument();
-
- try {
- document.insertString(document.getLength(), String.valueOf(object), null);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- getJTextPane().setCaretPosition(getJTextPane().getDocument().getLength());
- }
-
- /**
- * Inserts the provided component into the current outputArea.
- *
- * @param component the component to insert
- */
- private void insertJComponent(JComponent component) {
- Preconditions.checkNotNull(component);
-
- String componentUuid = SecurityUtil.generateUuid();
- Style cs = getJTextPane().getStyledDocument().addStyle(componentUuid, null);
- StyleConstants.setComponent(cs, component);
-
- try {
- getJTextPane().getStyledDocument().insertString(
- getJTextPane().getStyledDocument().getLength(), componentUuid, cs);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
-
- /**
- * Inserts the provided image icon into the current outputArea.
- *
- * @param imageIcon the iamge icon to insert
- */
- private void insertImageIcon(ImageIcon imageIcon) {
- Preconditions.checkNotNull(imageIcon);
- Preconditions.checkNotNull(getJTextPane());
-
- getJTextPane().insertIcon(imageIcon);
- }
-
- // ---------------------------
- // End document insert methods
- // ---------------------------
-
- /**
- * The frequency at which to play a typing sound effect if enabled.
- */
- private static final int TYPING_ANIMATION_SOUND_FREQUENCY = Props.printingAnimationSoundFrequency.getValue();
-
- /**
- * The number of characters appended for the the current printing animation.
- * Used to determine when to play a typing animation sound.
- */
- private final AtomicInteger typingAnimationCharsInserted = new AtomicInteger();
-
- /**
- * The file for the typing sound effect.
- */
- private final File typingSoundFile = StaticUtil.getStaticResource("typing.mp3");
-
- /**
- * Prints the string to the output area checking for
- * typing sound, finish printing, and other parameters.
- *
- * Note: this method is blocking and SHOULD NOT be used as a
- * substitute for the default print/println methods.
- *
- * @param line the string to append to the output area
- * @param typingSound whether the typing sound should be played
- */
- private void innerPrintString(String line, boolean typingSound) {
- Preconditions.checkNotNull(line);
-
- try {
- if (!linkedOutputPane.acquireLock()) {
- throw new FatalException("Failed to acquire output pane lock");
- }
-
- // todo sometimes this just breaks?
- for (String word : line.split("((?=\\s+))")) {
- String insertWord = UserDataManager.INSTANCE.isCapsMode() ? word.toUpperCase() : word;
-
- StyledDocument document = (StyledDocument) getJTextPane().getDocument();
- document.insertString(document.getLength(), insertWord, null);
-
- getJTextPane().setCaretPosition(getJTextPane().getDocument().getLength());
-
- if (typingAnimationCharsInserted.get() == TYPING_ANIMATION_SOUND_FREQUENCY) {
- if (!shouldFinishPrinting && typingSound) {
- GeneralAudioPlayer.playAudio(typingSoundFile);
- typingAnimationCharsInserted.set(0);
- }
- } else {
- typingAnimationCharsInserted.getAndIncrement();
- }
-
- if (!shouldFinishPrinting) {
- ThreadUtil.sleep(Props.printingAnimationWordTimeout.getValue());
- }
- }
-
- typingAnimationCharsInserted.set(0);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- } finally {
- linkedOutputPane.releaseLock();
- }
- }
-
- // -----------------------
- // Document entity removal
- // -----------------------
-
- /**
- * The deafult number of elements in a document.
- */
- private static final int defaultDocumentEntities = 3;
-
- /**
- * The number of times to call {@link #removeLastElement()} from within {@link #removeLastEntity()}.
- */
- private static final int removeLastElementCalls = 2;
-
- /**
- * Removes the last entity added to the JTextPane by invoking {@link #removeLastElement()} twice due
- * to a new line always being printed last. If there are other elements present after the remove, a newline
- * is added back to the document.
- */
- public final void removeLastEntity() {
- try {
- ElementIterator iterator = new ElementIterator(getJTextPane().getStyledDocument());
- int count = 0;
- while (iterator.next() != null) count++;
-
- if (!linkedOutputPane.acquireLock()) {
- throw new FatalException("Failed to acquire output pane lock");
- }
-
- removeLastElement();
- removeLastElement();
- if (count > defaultDocumentEntities + removeLastElementCalls) println("");
-
- linkedOutputPane.releaseLock();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
-
- /**
- * Returns the last line of text on the linked JTextPane.
- * Text is easier to get and return as opposed to general components.
- *
- * @return the last line of text on the linked JTextPane
- */
- public final String getLastTextLine() {
- return linkedOutputPane.getStringUtil().getLastTextLine();
- }
-
- /**
- * Removes the last line added to the linked JTextPane such as a component, image icon, string, or newline.
- */
- private void removeLastElement() {
- linkedOutputPane.getStringUtil().removeLastElement();
- }
-
- // -----------------
- // Redirection logic
- // -----------------
-
- /**
- * The lock used to ensure output is properly written to the {@link #redirectionFile}
- * This also ensures that multiple redirections aren't performed at the same time.
- */
- private final Semaphore redirectionLock = new Semaphore(1);
-
- /**
- * The error message to print if redirection fails.
- */
- private static final String REDIRECTION_ERROR_MESSAGE = "Could not redirect output";
-
- /**
- * Writes the provided object to the redirection file instead of the JTextPane.
- *
- * @param object the object to invoke toString() on and write to the current redirectionFile
- */
- private void redirectionWrite(Object object) {
- Preconditions.checkNotNull(object);
-
- if (!redirectionFile.exists()) {
- if (!OsUtil.createFile(redirectionFile, true)) {
- println(REDIRECTION_ERROR_MESSAGE);
- println(object);
- return;
- }
- }
-
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(redirectionFile, true))) {
- redirectionLock.acquire();
- writer.write(String.valueOf(object));
- Logger.log(LogTag.CONSOLE_REDIRECTION, "Console output was redirected to: "
- + redirectionFile.getAbsolutePath());
- redirectionLock.release();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
-
- /**
- * The escaped string.
- */
- private static final String ESCAPED = "Escaped";
-
- /**
- * Stops all threads invoked, sets the userInputMode to false,
- * stops any audio playing, and finishes printing anything in the printing lists.
- */
- public final void escapeThreads() {
- killThreads();
- escapeWrapShell = true;
- GeneralAudioPlayer.stopGeneralAudio();
- YouTubeDownloadManager.INSTANCE.cancelAllActiveDownloads();
- Console.INSTANCE.stopDancing();
- shouldFinishPrinting = true;
- println(ESCAPED);
- resetHandlers();
- }
-
- /**
- * Resets the handle iterations and redirection handler.
- */
- public void resetHandlers() {
- handleIterations = 0;
- redirectionHandler = null;
- }
-
- /**
- * The iteration the current handler is on.
- */
- private int handleIterations = 0;
-
- /**
- * Returns the current handle iteration.
- *
- * @return the current handle iteration
- */
- public int getHandleIterations() {
- return handleIterations;
- }
-
- /**
- * Sets the current handle iteration.
- *
- * @param handleIterations the current handle iteration
- */
- public void setHandleIterations(int handleIterations) {
- this.handleIterations = handleIterations;
- }
-
- /**
- * The current handler to send the input to.
- */
- private Class> redirectionHandler;
-
- /**
- * Returns the current redirection handler.
- *
- * @return the current redirection handler
- */
- public Class> getRedirectionHandler() {
- return redirectionHandler;
- }
-
- /**
- * Sets the current redirection handler.
- *
- * @param redirectionHandler the current redirection handler
- */
- public void setRedirectionHandler(Class> redirectionHandler) {
- Preconditions.checkNotNull(redirectionHandler);
-
- this.redirectionHandler = redirectionHandler;
- }
-
- /**
- * Returns the current user issued command.
- *
- * @return the current user issued command
- */
- public final String getCommand() {
- return this.command;
- }
-
- /**
- * Determines if the current command equals the provided text ignoring case.
- *
- * @param compare the string to check for case-insensitive equality to command
- * @return if the current command equals the provided text ignoring case
- */
- protected boolean commandIs(String compare) {
- Preconditions.checkNotNull(compare);
-
- return this.command.equalsIgnoreCase(compare);
- }
-
- /**
- * Returns whether the arguments array contains the expected number of arguments.
- * For example, if the user entered "consolidate windows middle" the command is "consolidate"
- * and the args are "windows" and "middle".
- *
- * @param expectedSize the expected size of the command arguments
- * @return whether the arguments array contains the expected number of arguments
- */
- protected boolean checkArgsLength(int expectedSize) {
- return args.size() == expectedSize;
- }
-
- /**
- * Returns the command argument at the provided index.
- * Returns null if the index is out of bounds instead of throwing.
- *
- * @param index the index to retrieve the command argument of
- * @return the command argument at the provided index
- */
- protected String getArg(int index) {
- Preconditions.checkArgument(index >= 0);
- Preconditions.checkArgument(index < args.size());
-
- return args.get(index);
- }
-
- /**
- * Returns the size of the arguments list.
- *
- * @return the size of the arguments list
- */
- protected int getArgsSize() {
- return args.size();
- }
-
- /**
- * Returns whether there are no args associated with the most recently issued command.
- *
- * @return whether there are no args associated with the most recently issued command
- */
- protected boolean noArgs() {
- return args.isEmpty();
- }
-
- /**
- * Returns the arguments in String form separated by spaces.
- *
- * @return the arguments in String form separated by spaces
- */
- protected String argsToString() {
- StringBuilder sb = new StringBuilder();
-
- for (int i = 0 ; i < args.size() ; i++) {
- sb.append(args.get(i));
- if (i != args.size() - 1) sb.append(CyderStrings.space);
- }
-
- return sb.toString();
- }
-
- /**
- * Returns the original user input, that of the command followed by the arguments.
- *
- * @return the original user input, that of the command followed by the arguments
- */
- protected String commandAndArgsToString() {
- return (this.command.trim() + CyderStrings.space + argsToString()).trim();
- }
-
- /**
- * Returns whether the provided string matches the command and
- * arguments strung together with whitespace removed.
- *
- * @param match the string to match to
- * @return whether the provided string matched the command args with whitespace removed
- */
- protected boolean inputIgnoringSpacesMatches(String match) {
- Preconditions.checkNotNull(match);
-
- return match.replaceAll(CyderRegexPatterns.whiteSpaceRegex, "").equalsIgnoreCase(
- commandAndArgsToString().replaceAll(CyderRegexPatterns.whiteSpaceRegex, ""));
- }
-
- /**
- * Returns whether the current command and args to string starts with the provided string.
- *
- * @param startsWith the string
- * @return whether the current command and args to string starts with the provided string
- */
- protected boolean inputIgnoringSpacesAndCaseStartsWith(String startsWith) {
- Preconditions.checkNotNull(startsWith);
-
- return commandAndArgsToString().replaceAll(CyderRegexPatterns.whiteSpaceRegex, "").toLowerCase()
- .startsWith(startsWith.replaceAll(CyderRegexPatterns.whiteSpaceRegex, "").toLowerCase());
- }
-
- // -------------------------------------------
- // Utils for print methods and synchronization
- // -------------------------------------------
-
- /**
- * Returns whether a YouTube or bletchy thread is running.
- *
- * @return whether a YouTube or bletchy thread is running
- */
- @ForReadability
- private boolean threadsActive() {
- return YoutubeUuidCheckerManager.INSTANCE.hasActiveCheckers()
- || BletchyAnimationManager.INSTANCE.isActive();
- }
-
- // ---------------------
- // Generic print methods
- // ---------------------
-
- /**
- * The printing semaphore.
- */
- private final Semaphore printingSemaphore = new Semaphore(1);
-
- /**
- * Aqquires the printing lock.
- */
- private void acquirePrintingLock() {
- try {
- printingSemaphore.acquire();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
-
- /**
- * Releases the printing lock.
- */
- private void releasePrintingLock() {
- printingSemaphore.release();
- }
-
- /**
- * Prints the provided type.
- *
- * @param type the type to print
- */
- public final void print(T type) {
- Preconditions.checkNotNull(type);
-
- if (threadsActive()) {
- consolePriorityPrintingList.add(type);
- } else {
- consolePrintingList.add(type);
- }
- }
-
- /**
- * Prints the provided type followed by a newline.
- *
- * @param type the type to print
- */
- public final void println(T type) {
- Preconditions.checkNotNull(type);
-
- if (threadsActive()) {
- consolePriorityPrintingList.add(type);
- consolePriorityPrintingList.add(CyderStrings.newline);
- } else {
- acquirePrintingLock();
- consolePrintingList.add(type);
- consolePrintingList.add(CyderStrings.newline);
- releasePrintingLock();
- }
- }
-
- /**
- * Adds the provided type to the priority printing list.
- *
- * @param type the type to add to the priority printing list
- */
- public final void printPriority(T type) {
- Preconditions.checkNotNull(type);
-
- consolePriorityPrintingList.add(type);
- }
-
- /**
- * Adds the provided type and a newline to the priority printing list.
- *
- * @param type the type to add to the priority printing list
- */
- public final void printlnPriority(T type) {
- Preconditions.checkNotNull(type);
-
- consolePriorityPrintingList.add(type);
- consolePriorityPrintingList.add(CyderStrings.newline);
- }
-
- /**
- * Prints the provided String lines to the linked JTextPane.
- * Note that new lines are automatically added in this so the passed
- * array may be strings that do not end with new lines.
- *
- * @param lines the lines to print to the JTextPane
- */
- public final void printlns(String[] lines) {
- Arrays.stream(lines).forEach(this::println);
- }
-
- /**
- * Prints the provided String lines to the linked JTextPane.
- * Note that new lines are automatically added in this so the passed
- * array may be strings that do not end with new lines.
- *
- * @param lines the lines to print to the JTextPane
- */
- public final void printlns(List lines) {
- lines.forEach(this::println);
- }
-
- // -----------------------------------------------------------------
- // Printed labels which require font, font metric, font size,
- // and foreground updating as long as they are contained in the list
- // -----------------------------------------------------------------
-
- /**
- * The list of labels appended to the Console's text pane which require updating whenever
- * the following events occur:
- *
- *
- * User font changed
- * User font metric changed
- * User font size changed
- * User foreground color changed
- *
- */
- private final ArrayList printedLabels = new ArrayList<>();
-
- /**
- * Adds the providede label to the printed labels list. This label will have its properties updated when
- * the following events occurs:
- *
- *
- * User font changed
- * User font metric changed
- * User font size changed
- * User foreground color changed
- *
- *
- * @param label the label to update when the outlined events occur
- */
- public void addPrintedLabel(JLabel label) {
- Preconditions.checkNotNull(label);
- Preconditions.checkArgument(!printedLabels.contains(label));
-
- printedLabels.add(label);
- }
-
- /**
- * Removes the provided label from the printed labels list. This label will no longer be updated.
- *
- * @param label the label to remove from the list
- */
- public void removePrintedLabel(JLabel label) {
- Preconditions.checkNotNull(label);
- Preconditions.checkArgument(printedLabels.contains(label));
-
- printedLabels.remove(label);
- }
-
- /**
- * Clears the printed labels list. These labels will no longer be updated if one of the following events occurs:
- *
- *
- * User font changed
- * User font metric changed
- * User font size changed
- * User foreground color changed
- *
- */
- public void clearPrintedLabels() {
- printedLabels.clear();
- }
-
- /**
- * Refreshes the following properties of all labels current in the printed labels list:
- *
- *
- * Foreground
- * Font
- * Font metric
- * Font size
- *
- */
- public void refreshPrintedLabels() {
- printedLabels.forEach(label -> {
- label.setForeground(UserDataManager.INSTANCE.getForegroundColor());
- label.setFont(Console.INSTANCE.generateUserFont());
- });
- }
-}
\ No newline at end of file
diff --git a/src/main/java/cyder/handlers/input/ColorHandler.java b/src/main/java/cyder/handlers/input/ColorHandler.java
deleted file mode 100644
index 3ea4c146e..000000000
--- a/src/main/java/cyder/handlers/input/ColorHandler.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.strings.CyderStrings;
-import cyder.ui.field.CyderCaret;
-import cyder.user.UserData;
-import cyder.user.UserDataManager;
-import cyder.user.UserFile;
-import cyder.utils.ColorUtil;
-import cyder.utils.ImageUtil;
-
-import javax.imageio.ImageIO;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.io.File;
-
-/**
- * A handler for commands which change color/font throughout Cyder.
- */
-public class ColorHandler extends InputHandler {
- /**
- * Suppress default constructor
- */
- private ColorHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"backgroundcolor", "fix foreground", "foreground", "repaint"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().inputIgnoringSpacesAndCaseStartsWith("backgroundcolor")) {
- if (getInputHandler().checkArgsLength(1)) {
- try {
- int w = Console.INSTANCE.getConsoleCyderFrame().getWidth();
- int h = Console.INSTANCE.getConsoleCyderFrame().getHeight();
-
- if (UserDataManager.INSTANCE.isFullscreen()) {
- Rectangle monitorBounds = Console.INSTANCE.getConsoleCyderFrame()
- .getMonitorBounds().getBounds();
-
- w = (int) monitorBounds.getWidth();
- h = (int) monitorBounds.getHeight();
- }
-
- String colorString = getInputHandler().getArg(0);
- Color color = ColorUtil.hexStringToColor(colorString);
- BufferedImage saveImage = ImageUtil.bufferedImageFromColor(color, w, h);
-
- String saveName = "Solid_" + getInputHandler().getArg(0)
- + "_Background" + Extension.PNG.getExtension();
-
- File saveFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.BACKGROUNDS.getName(), saveName);
-
- ImageIO.write(saveImage, Extension.PNG.getExtensionWithoutPeriod(), saveFile);
-
- getInputHandler().println("Background generated, set, and saved as a separate background file.");
-
- Console.INSTANCE.setBackgroundFile(saveFile);
- } catch (Exception ignored) {
- getInputHandler().println("Background color command usage: backgroundcolor EC407A");
- }
- } else {
- getInputHandler().println("Background color command usage: backgroundcolor EC407A");
- }
- } else if (getInputHandler().inputIgnoringSpacesMatches("fixforeground")) {
- try {
- Color backgroundDominantColor = ColorUtil.getDominantColor(ImageUtil.read(
- Console.INSTANCE.getCurrentBackground().getReferenceFile()));
-
- if (shouldUseLightColor(backgroundDominantColor)) {
- Console.INSTANCE.getOutputArea().setForeground(CyderColors.defaultLightModeTextColor);
- Console.INSTANCE.getInputField().setForeground(CyderColors.defaultLightModeTextColor);
- Console.INSTANCE.getInputField().setCaretColor(CyderColors.defaultLightModeTextColor);
- Console.INSTANCE.getInputField()
- .setCaret(new CyderCaret(CyderColors.defaultLightModeTextColor));
- UserDataManager.INSTANCE.setForegroundColor(CyderColors.defaultLightModeTextColor);
- } else {
- Console.INSTANCE.getOutputArea().setForeground(CyderColors.defaultDarkModeTextColor);
- Console.INSTANCE.getInputField().setForeground(CyderColors.defaultDarkModeTextColor);
- Console.INSTANCE.getInputField().setCaretColor(CyderColors.defaultDarkModeTextColor);
- Console.INSTANCE.getInputField()
- .setCaret(new CyderCaret(CyderColors.defaultDarkModeTextColor));
- UserDataManager.INSTANCE.setForegroundColor(CyderColors.defaultDarkModeTextColor);
- }
-
- UserData.foregroundColor.getOnChangeRunnable().ifPresent(Runnable::run);
- getInputHandler().println("Foreground fixed");
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- ret = false;
- }
- } else if (getInputHandler().commandIs("repaint")) {
- Console.INSTANCE.revalidate(false, false);
- getInputHandler().println("Console repainted");
- } else {
- ret = false;
- }
-
- return ret;
- }
-
- /**
- * Returns whether the text color to be layered over the
- * provided background color should be a light mode color.
- *
- * @param backgroundColor the background color to find a suitable text color for
- * @return whether the text color should be a light mode color
- */
- private static boolean shouldUseLightColor(Color backgroundColor) {
- return (backgroundColor.getRed() * 0.299 + backgroundColor.getGreen()
- * 0.587 + backgroundColor.getBlue() * 0.114) > 186;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/FileHandler.java b/src/main/java/cyder/handlers/input/FileHandler.java
deleted file mode 100644
index ca19c251e..000000000
--- a/src/main/java/cyder/handlers/input/FileHandler.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.enumerations.Dynamic;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.DosAttribute;
-import cyder.files.FileUtil;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.utils.OsUtil;
-import cyder.utils.SpotlightUtil;
-
-import java.io.File;
-import java.util.Arrays;
-
-/**
- * A handler related to files and manipulation of them.
- */
-public class FileHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private FileHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"wipe logs", "open current log", "open last log", "wipe", "cmd", "dos attributes"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().inputIgnoringSpacesMatches("wipe logs")) {
- OsUtil.deleteFile(Dynamic.buildDynamic(Dynamic.LOGS.getFileName()));
- getInputHandler().println("Logs wiped");
- } else if (getInputHandler().inputIgnoringSpacesMatches("open current log")) {
- FileUtil.openResourceUsingNativeProgram(Logger.getCurrentLogFile().getAbsolutePath());
- } else if (getInputHandler().inputIgnoringSpacesMatches("open last log")) {
- File[] logs = Logger.getCurrentLogFile().getParentFile().listFiles();
-
- if (logs != null) {
- if (logs.length == 1) {
- getInputHandler().println("No previous logs found");
- } else if (logs.length > 1) {
- FileUtil.openResourceUsingNativeProgram(logs[logs.length - 2].getAbsolutePath());
- }
- }
- } else if (getInputHandler().inputIgnoringSpacesMatches("wipe spot lights")) {
- SpotlightUtil.wipeSpotlights();
- } else if (getInputHandler().commandIs("wipe")) {
- if (getInputHandler().checkArgsLength(1)) {
- File requestedDeleteFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), getInputHandler().getArg(0));
- if (requestedDeleteFile.exists()) {
- if (requestedDeleteFile.isDirectory()) {
- if (OsUtil.deleteFile(requestedDeleteFile)) {
- getInputHandler().println("Successfully deleted: "
- + requestedDeleteFile.getAbsolutePath());
- } else {
- getInputHandler().println("Could not delete folder at this time");
- }
- } else if (requestedDeleteFile.isFile()) {
- if (OsUtil.deleteFile(requestedDeleteFile)) {
- getInputHandler().println("Successfully deleted "
- + requestedDeleteFile.getAbsolutePath());
- } else {
- getInputHandler().println("Unable to delete file at this time");
- }
- } else {
- throw new IllegalStateException(
- "File is not a file nor directory. " + CyderStrings.EUROPEAN_TOY_MAKER);
- }
- } else {
- getInputHandler().println("Requested file does not exist: "
- + requestedDeleteFile.getAbsolutePath());
- }
- } else {
- getInputHandler().print("Wipe command usage: wipe [directory/file within your user directory]");
- }
- } else if (getInputHandler().commandIs("cmd")) {
- OsUtil.openShell();
- } else if (getInputHandler().inputIgnoringSpacesAndCaseStartsWith("dos attributes")) {
- if (getInputHandler().checkArgsLength(2)) {
- File file = new File(getInputHandler().getArg(1));
- if (file.exists()) {
- getInputHandler().println("DOS attributes for \"" + FileUtil.getFilename(file) + "\"");
- getInputHandler().println("------------------------");
- Arrays.stream(DosAttribute.values()).forEach(dosAttribute ->
- getInputHandler().println(dosAttribute.getMethodName() + ": "
- + DosAttribute.getAttribute(file, dosAttribute)));
- } else {
- getInputHandler().println("Provided file does not exist, absolute path: " + file.getAbsolutePath());
- getInputHandler().print("Cwd: " + new File(".").getAbsolutePath());
- }
- } else {
- getInputHandler().println("DOS attributes command usage: dos attributes path/to/my/file.txt");
- }
- } else {
- ret = false;
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/FrameMovementHandler.java b/src/main/java/cyder/handlers/input/FrameMovementHandler.java
deleted file mode 100644
index 944e5a553..000000000
--- a/src/main/java/cyder/handlers/input/FrameMovementHandler.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.ui.UiConstants;
-import cyder.ui.UiUtil;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.ScreenPosition;
-
-import java.awt.*;
-
-/**
- * Handles CyderFrame and Console movement commands.
- */
-public class FrameMovementHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private FrameMovementHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The degrees to rotate the console pane by when making a frame askew.
- */
- private static final int ASKEW_DEGREE = 5;
-
- @Handle({"top left", "top right", "bottom left", "bottom right",
- "consolidate windows", "dance", "hide", "askew", "barrel roll", "middle", "center"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().inputIgnoringSpacesMatches("topleft")) {
- Console.INSTANCE.setLocationOnScreen(ScreenPosition.TRUE_TOP_LEFT);
- } else if (getInputHandler().inputIgnoringSpacesMatches("topright")) {
- Console.INSTANCE.setLocationOnScreen(ScreenPosition.TRUE_TOP_RIGHT);
- } else if (getInputHandler().inputIgnoringSpacesMatches("bottomleft")) {
- Console.INSTANCE.setLocationOnScreen(ScreenPosition.TRUE_BOTTOM_LEFT);
- } else if (getInputHandler().inputIgnoringSpacesMatches("bottomright")) {
- Console.INSTANCE.setLocationOnScreen(ScreenPosition.TRUE_BOTTOM_RIGHT);
- } else if (getInputHandler().inputIgnoringSpacesMatches("middle")
- || getInputHandler().inputIgnoringSpacesMatches("center")) {
- Console.INSTANCE.setLocationOnScreen(ScreenPosition.TRUE_CENTER);
- } else if (getInputHandler().inputIgnoringSpacesMatches("frame titles")) {
- for (Frame f : UiUtil.getFrames()) {
- getInputHandler().println(f.getTitle());
- }
- } else if (getInputHandler().commandIs("consolidate")
- && getInputHandler().getArg(0).equalsIgnoreCase("windows")) {
- if (getInputHandler().checkArgsLength(3)) {
- if (getInputHandler().getArg(1).equalsIgnoreCase("top")
- && getInputHandler().getArg(2).equalsIgnoreCase("right")) {
- for (CyderFrame f : UiUtil.getCyderFrames()) {
- if (f.getState() == UiConstants.FRAME_ICONIFIED) {
- f.setState(UiConstants.FRAME_NORMAL);
- }
-
- int anchorX = Console.INSTANCE.getConsoleCyderFrame().getX()
- + Console.INSTANCE.getConsoleCyderFrame().getWidth()
- - f.getWidth();
- int anchorY = Console.INSTANCE.getConsoleCyderFrame().getY();
-
- f.setRestorePoint(new Point(anchorX, anchorY));
- f.setLocation(anchorX, anchorY);
- }
- } else if (getInputHandler().getArg(1).equalsIgnoreCase("bottom")
- && getInputHandler().getArg(2).equalsIgnoreCase("right")) {
- for (CyderFrame f : UiUtil.getCyderFrames()) {
- if (f.getState() == UiConstants.FRAME_ICONIFIED) {
- f.setState(UiConstants.FRAME_NORMAL);
- }
-
- int anchorX = Console.INSTANCE.getConsoleCyderFrame().getX()
- + Console.INSTANCE.getConsoleCyderFrame().getWidth()
- - f.getWidth();
- int anchorY = Console.INSTANCE.getConsoleCyderFrame().getY()
- + Console.INSTANCE.getConsoleCyderFrame().getHeight()
- - f.getHeight();
-
- f.setRestorePoint(new Point(anchorX, anchorY));
- f.setLocation(anchorX, anchorY);
- }
- } else if (getInputHandler().getArg(1).equalsIgnoreCase("bottom")
- && getInputHandler().getArg(2).equalsIgnoreCase("left")) {
- for (CyderFrame f : UiUtil.getCyderFrames()) {
- if (f.getState() == UiConstants.FRAME_ICONIFIED) {
- f.setState(UiConstants.FRAME_NORMAL);
- }
-
- int anchorX = Console.INSTANCE.getConsoleCyderFrame().getX();
- int anchorY = Console.INSTANCE.getConsoleCyderFrame().getY()
- + Console.INSTANCE.getConsoleCyderFrame().getHeight()
- - f.getHeight();
-
- f.setRestorePoint(new Point(anchorX, anchorY));
- f.setLocation(anchorX, anchorY);
- }
- } else if (getInputHandler().getArg(1).equalsIgnoreCase("top")
- && getInputHandler().getArg(2).equalsIgnoreCase("left")) {
- for (CyderFrame f : UiUtil.getCyderFrames()) {
- if (f.getState() == UiConstants.FRAME_ICONIFIED) {
- f.setState(UiConstants.FRAME_NORMAL);
- }
-
- int anchorX = Console.INSTANCE.getConsoleCyderFrame().getX();
- int anchorY = Console.INSTANCE.getConsoleCyderFrame().getY();
-
- f.setRestorePoint(new Point(anchorX, anchorY));
- f.setLocation(anchorX, anchorY);
- }
- } else {
- getInputHandler().println("Command usage: consolidate windows top left");
- }
- } else if (getInputHandler().checkArgsLength(2)
- && (getInputHandler().getArg(1).equalsIgnoreCase("center")
- || getInputHandler().getArg(1).equalsIgnoreCase("middle"))) {
- Point consoleCenter = Console.INSTANCE.getConsoleCyderFrame().getCenterPointOnScreen();
- int x = (int) consoleCenter.getX();
- int y = (int) consoleCenter.getY();
-
- for (CyderFrame f : UiUtil.getCyderFrames()) {
- if (f == Console.INSTANCE.getConsoleCyderFrame()) {
- continue;
- }
-
- if (f.getState() == UiConstants.FRAME_ICONIFIED) {
- f.setState(UiConstants.FRAME_NORMAL);
- }
-
- int anchorX = x - f.getWidth() / 2;
- int anchorY = y - f.getHeight() / 2;
-
- f.setRestorePoint(new Point(anchorX, anchorY));
- f.setLocation(anchorX, anchorY);
- }
- } else {
- getInputHandler().println("Command usage: consolidate windows top left");
- }
- } else if (getInputHandler().commandIs("dance")) {
- Console.INSTANCE.dance();
- } else if (getInputHandler().commandIs("hide")) {
- Console.INSTANCE.getConsoleCyderFrame().minimizeAndIconify();
- } else if (getInputHandler().inputIgnoringSpacesMatches("barrelroll")) {
- Console.INSTANCE.barrelRoll();
- } else if (getInputHandler().commandIs("askew")) {
- Console.INSTANCE.getConsoleCyderFrame().rotateBackground(ASKEW_DEGREE);
- } else {
- ret = false;
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/GeneralPrintHandler.java b/src/main/java/cyder/handlers/input/GeneralPrintHandler.java
deleted file mode 100644
index a59f09055..000000000
--- a/src/main/java/cyder/handlers/input/GeneralPrintHandler.java
+++ /dev/null
@@ -1,274 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.constants.CyderRegexPatterns;
-import cyder.enumerations.Suggestion;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.math.NumberUtil;
-import cyder.network.IpDataManager;
-import cyder.parsers.ip.IpData;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.BletchyAnimationManager;
-import cyder.threads.CyderThreadRunner;
-import cyder.time.TimeUtil;
-import cyder.user.UserDataManager;
-import cyder.utils.AstronomyUtil;
-import cyder.utils.ImageUtil;
-import cyder.utils.OsUtil;
-
-import javax.swing.*;
-import java.io.IOException;
-import java.security.SecureRandom;
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.temporal.TemporalAdjusters;
-import java.util.Calendar;
-import java.util.Optional;
-
-/**
- * A handler for printing out general response strings.
- */
-public class GeneralPrintHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private GeneralPrintHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().commandIs("shakespeare")) {
- if (NumberUtil.generateRandomInt(0, 1) == 1) {
- getInputHandler().println("Glamis hath murdered sleep, "
- + "and therefore Cawdor shall sleep no more, Macbeth shall sleep no more.");
- } else {
- getInputHandler().println("To be, or not to be, that is the question: Whether 'tis nobler in "
- + "the mind to suffer the slings and arrows of "
- + "outrageous fortune, or to take arms against a sea of troubles and by opposing end them.");
- }
- } else if (getInputHandler().commandIs("asdf")) {
- getInputHandler().println("Who is the spiciest meme lord?");
- } else if (getInputHandler().commandIs("thor")) {
- getInputHandler().println("Piss off, ghost.");
- } else if (getInputHandler().commandIs("alextrebek")) {
- getInputHandler().println("Do you mean who is alex trebek?");
- } else if (StringUtil.isPalindrome(getInputHandler()
- .getCommand().replaceAll(CyderRegexPatterns.whiteSpaceRegex, ""))
- && getInputHandler().getCommand().length() > 3) {
- getInputHandler().println("Nice palindrome.");
- } else if (getInputHandler().commandIs("coinflip")) {
- double randGauss = new SecureRandom().nextGaussian();
- if (randGauss <= 0.0001) {
- getInputHandler().println("You're not going to believe this, but it landed on its side.");
- } else if (randGauss <= 0.5) {
- getInputHandler().println("It's Heads!");
- } else {
- getInputHandler().println("It's Tails!");
- }
- } else if (getInputHandler().commandIs("hello")
- || getInputHandler().commandIs("hi")) {
- switch (NumberUtil.generateRandomInt(1, 7)) {
- case 1:
- getInputHandler().println("Hello, " + UserDataManager.INSTANCE.getUsername() + ".");
- break;
- case 2:
- if (TimeUtil.isEvening()) {
- getInputHandler().println("Good evening, "
- + UserDataManager.INSTANCE.getUsername() + ". How can I help?");
- } else if (TimeUtil.isMorning()) {
- getInputHandler().println("Good morning, "
- + UserDataManager.INSTANCE.getUsername() + ". How can I help?");
- } else {
- getInputHandler().println("Good afternoon, "
- + UserDataManager.INSTANCE.getUsername() + ". How can I help?");
- }
- break;
- case 3:
- getInputHandler().println("What's up, " + UserDataManager.INSTANCE.getUsername() + "?");
- break;
- case 4:
- getInputHandler().println("How are you doing, " + UserDataManager.INSTANCE.getUsername() + "?");
- break;
- case 5:
- getInputHandler().println("Greetings, " + UserDataManager.INSTANCE.getUsername() + ".");
- break;
- case 6:
- getInputHandler().println("I'm here....");
- break;
- case 7:
- getInputHandler().println("Go ahead...");
- break;
- }
- } else if (getInputHandler().commandIs("bye")) {
- getInputHandler().println("Just say you won't let go.");
- } else if (getInputHandler().commandIs("time")) {
- getInputHandler().println(TimeUtil.weatherTime());
- } else if (getInputHandler().commandIs("lol")) {
- getInputHandler().println("My memes are better.");
- } else if (getInputHandler().commandIs("thanks")) {
- getInputHandler().println("You're welcome.");
- } else if (getInputHandler().commandIs("name")) {
- getInputHandler().println("My name is Cyder. I am a tool built by"
- + " Nathan Cheshire for programmers and advanced users.");
- } else if (getInputHandler().commandIs("k")) {
- getInputHandler().println("Fun Fact: the letter \"K\" comes from the Greek letter kappa, which was taken "
- + "from the Semitic kap, the symbol for an open hand. It is this very hand which "
- + "will be slapping you in the face for saying \"k\" to me.");
- } else if (getInputHandler().commandIs("no")) {
- getInputHandler().println("Yes");
- } else if (getInputHandler().commandIs("nope")) {
- getInputHandler().println("yep");
- } else if (getInputHandler().commandIs("yes")) {
- getInputHandler().println("no");
- } else if (getInputHandler().commandIs("yep")) {
- getInputHandler().println("nope");
- } else if (getInputHandler().commandIs("jarvis")) {
- getInputHandler().println("*scoffs in Java* primitive loser AI");
- } else if (getInputHandler().commandIs("thanksgiving")) {
- int year = Calendar.getInstance().get(Calendar.YEAR);
- LocalDate RealTG = LocalDate.of(year, 11, 1)
- .with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.THURSDAY));
- getInputHandler().println("Thanksgiving this year is on the " + RealTG.getDayOfMonth() + " of November.");
- } else if (getInputHandler().commandIs("fibonacci")) {
- for (long i : NumberUtil.computeFibonacci(0, 1, 100))
- getInputHandler().println(i);
- } else if (getInputHandler().commandIs("break;")) {
- getInputHandler().println("Thankfully my pure console based infinite while loop days are over. <3 Nathan");
- } else if (getInputHandler().commandIs("why")) {
- getInputHandler().println("Why not?");
- } else if (getInputHandler().commandIs("why not")) {
- getInputHandler().println("Why?");
- } else if (getInputHandler().commandIs("groovy")) {
- getInputHandler().println("Kotlin is the best JVM lang.... I mean, Java is obviously the best!");
- } else if (getInputHandler().commandIs("&&")) {
- getInputHandler().println("||");
- } else if (getInputHandler().commandIs("||")) {
- getInputHandler().println("&&");
- } else if (getInputHandler().commandIs("&")) {
- getInputHandler().println("|");
- } else if (getInputHandler().commandIs("|")) {
- getInputHandler().println("&");
- } else if (getInputHandler().commandIs("espanol")) {
- getInputHandler().println("Tu hablas Espanol? Yo estudio Espanol mas-o-menos. Hay tu mi amigo?");
- } else if (getInputHandler().commandIs("look")) {
- getInputHandler().println("L()()K ---->> !FREE STUFF! <<---- L()()K");
- } else if (getInputHandler().commandIs("cyder")) {
- getInputHandler().println("That's my name, don't wear it out pls");
- } else if (getInputHandler().commandIs("home")) {
- getInputHandler().println("There's no place like localhost/127.0.0.1");
- } else if (getInputHandler().commandIs("love")) {
- getInputHandler().println("Sorry, " + UserDataManager.INSTANCE.getUsername() +
- ", but I don't understand human emotions or affections.");
- } else if (getInputHandler().commandIs("loop")) {
- getInputHandler().println("InputHandler.handle(\"loop\", true);");
- } else if (getInputHandler().commandIs("story")) {
- getInputHandler().println("It was a lazy day. Cyder was enjoying a deep sleep when suddenly "
- + UserDataManager.INSTANCE.getUsername() + " started talking to Cyder."
- + " It was at this moment that Cyder knew its day had been ruined.");
- } else if (getInputHandler().commandIs("i hate you")) {
- getInputHandler().println("That's not very nice.");
- } else if (getInputHandler().commandIs("easter")) {
- getInputHandler().println("Easter Sunday is on " + TimeUtil.getEasterSundayString());
- } else if (getInputHandler().commandIs("age")) {
- BletchyAnimationManager.INSTANCE.bletchy("I am somewhere between 69 and 420 years old.",
- true, 50, false);
- } else if (getInputHandler().commandIs("scrub")) {
- BletchyAnimationManager.INSTANCE.bletchy(
- "No you!", false, 50, true);
- } else if (getInputHandler().commandIs("bletchy")) {
- BletchyAnimationManager.INSTANCE.bletchy(
- getInputHandler().argsToString(), false, 50, true);
- } else if (getInputHandler().commandIs("dst")) {
- CyderThreadRunner.submit(() -> {
- IpData data = IpDataManager.INSTANCE.getIpData();
-
- String location = data.getCity() + ", " + data.getRegion() + ", " + data.getCountry_name();
- if (data.getTime_zone().isIs_dst()) {
- getInputHandler().println("DST is underway in " + location + ".");
- } else {
- getInputHandler().println("DST is not underway in " + location + ".");
- }
- }, "DST Checker");
- } else if ((getInputHandler().commandAndArgsToString()
- .replaceAll(CyderRegexPatterns.whiteSpaceRegex, "").startsWith("longword"))) {
- for (int i = 0 ; i < getInputHandler().getArgsSize() ; i++) {
- getInputHandler().print("pneumonoultramicroscopicsilicovolcanoconiosis");
- }
-
- getInputHandler().println("");
- } else if (getInputHandler().commandIs("pwd")) {
- getInputHandler().println(OsUtil.USER_DIR);
- } else if (getInputHandler().commandIs("whoami")) {
- getInputHandler().println(OsUtil.getComputerName() + OsUtil.FILE_SEP
- + StringUtil.capsFirstWords(UserDataManager.INSTANCE.getUsername()));
- } else if (getInputHandler().commandIs("jarmode")) {
- getInputHandler().println(OsUtil.JAR_MODE ? "Cyder is currently running from a JAR"
- : "Cyder is currently running from a non-JAR source");
- } else if (getInputHandler().commandIs("clc") ||
- getInputHandler().commandIs("cls") ||
- getInputHandler().inputIgnoringSpacesMatches("clear")) {
- Console.INSTANCE.getOutputArea().setText("");
- } else if (getInputHandler().commandIs("throw")) {
- ExceptionHandler.handle(new Exception("Big boi exceptions; " +
- "\"I chase your love around figure 8, I need you more than I can take\""));
- } else if (getInputHandler().commandIs("clearops")) {
- Console.INSTANCE.clearCommandHistory();
- Logger.log(LogTag.HANDLE_METHOD, "User cleared command history");
- getInputHandler().println("Command history reset");
- } else if (getInputHandler().commandIs("anagram")) {
- if (getInputHandler().checkArgsLength(2)) {
- if (StringUtil.areAnagrams(getInputHandler().getArg(0), getInputHandler().getArg(1))) {
- getInputHandler().println(getInputHandler().getArg(0) + " and "
- + getInputHandler().getArg(1) + " are anagrams of each other");
- } else {
- getInputHandler().println(getInputHandler().getArg(0) + " and "
- + getInputHandler().getArg(1) + " are not anagrams of each other");
- }
- } else {
- getInputHandler().println("Anagram usage: anagram word1 word2");
- }
- } else if (getInputHandler().commandIs("help")) {
- getInputHandler().println("Try typing: ");
-
- for (Suggestion suggestion : Suggestion.values()) {
- getInputHandler().println(CyderStrings.BULLET_POINT + "\t" + suggestion.getCommand()
- + "\n\tDescription: " + suggestion.getDescription());
- }
- } else if (getInputHandler().commandAndArgsToString().matches(".*tell.*joke.*")) {
- getInputHandler().println("Knock Knock\nRace condition\nWho's there?");
- } else if (getInputHandler().commandIs("echo")
- || getInputHandler().commandIs("print")
- || getInputHandler().commandIs("println")) {
- getInputHandler().println(getInputHandler().argsToString());
- } else if (getInputHandler().commandIs("moon")) {
- Optional currentMoonPhaseOptional = AstronomyUtil.getCurrentMoonPhase();
-
- if (currentMoonPhaseOptional.isPresent()) {
- AstronomyUtil.MoonPhase currentMoonPhase = currentMoonPhaseOptional.get();
-
- try {
- getInputHandler().println(new ImageIcon(ImageUtil.read(currentMoonPhase.imageUrl())));
- } catch (IOException e) {
- ExceptionHandler.handle(e);
- }
-
- getInputHandler().println("Moon phase: " + currentMoonPhase.phase());
- getInputHandler().println("Illumination: " + currentMoonPhase.illumination() + "%");
- } else {
- getInputHandler().print("Could not find current moon phase");
- }
- } else {
- ret = false;
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/GitHandler.java b/src/main/java/cyder/handlers/input/GitHandler.java
deleted file mode 100644
index 8eef4706d..000000000
--- a/src/main/java/cyder/handlers/input/GitHandler.java
+++ /dev/null
@@ -1,189 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Handle;
-import cyder.constants.CyderUrls;
-import cyder.exceptions.IllegalMethodException;
-import cyder.github.GitHubUtil;
-import cyder.github.parsers.Issue;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.network.NetworkUtil;
-import cyder.process.ProcessUtil;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.user.UserFile;
-import cyder.user.UserUtil;
-import cyder.utils.OsUtil;
-
-import java.util.Map;
-import java.util.concurrent.Future;
-
-import static cyder.strings.CyderStrings.quote;
-import static cyder.strings.CyderStrings.space;
-
-/**
- * A handler for commands and inputs related to git/github/gitlab.
- */
-public class GitHandler extends InputHandler {
- /**
- * The git command.
- */
- private static final String GIT = "git";
-
- /**
- * The git clone command.
- */
- private static final String GIT_CLONE = "git clone";
-
- /**
- * The issue string separator.
- */
- private static final String issueSeparator = "----------------------------------------";
-
- /**
- * The name of the github issue printer thread.
- */
- private static final String GITHUB_ISSUE_PRINTER_THREAD_NAME = "Cyder GitHub Issue Printer";
-
- /**
- * Suppress default constructor.
- */
- private GitHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"gitme", "github", "issues", "git clone", "languages"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().commandIs("gitme")) {
- gitme();
- } else if (getInputHandler().commandIs("github")) {
- NetworkUtil.openUrl(CyderUrls.CYDER_SOURCE);
- } else if (getInputHandler().commandIs("issues")) {
- printIssues();
- } else if (getInputHandler().inputIgnoringSpacesAndCaseStartsWith(GIT_CLONE)) {
- cloneRepo();
- } else if (getInputHandler().commandIs("languages")) {
- printLanguagesUsedByCyder();
- } else {
- ret = false;
- }
-
- return ret;
- }
-
- @ForReadability
- private static void printLanguagesUsedByCyder() {
- Map map = GitHubUtil.getLanguages();
-
- getInputHandler().println("Cyder uses the following languages:");
- for (Map.Entry entry : map.entrySet()) {
- getInputHandler().println(entry.getKey() + " takes up " + OsUtil.formatBytes(entry.getValue()));
- }
- }
-
- @ForReadability
- private static void cloneRepo() {
- String repo = getInputHandler().commandAndArgsToString().substring(GIT_CLONE.length()).trim();
- if (repo.isEmpty()) {
- getInputHandler().println("Git clone usage: git clone [repository remote link]");
- return;
- }
-
- String threadName = "Git Cloner, repo: " + repo;
- CyderThreadRunner.submit(() -> {
- try {
- Future futureCloned = GitHubUtil.cloneRepoToDirectory(repo,
- UserUtil.getUserFile(UserFile.FILES));
-
- while (!futureCloned.isDone()) Thread.onSpinWait();
- boolean cloned = futureCloned.get();
- if (cloned) {
- getInputHandler().println("Clone successfully finished");
- } else {
- getInputHandler().println("Clone failed");
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, threadName);
- }
-
- /**
- * Generates and returns the commands to send to a process
- * builder to perform a git add for all files in the current directory.
- *
- * @return the commands for a git add
- */
- private static String[] generateGitAddCommand() {
- return new String[]{GIT, "add", "."};
- }
-
- /**
- * Generates and returns the command to send a process builder to perform
- * a git push for all local yet not pushed commits.
- * Note this assumes the remote branch currently being tracked is named "main".
- *
- * @return the commands for a git push
- */
- private static String[] generateGitPushCommand() {
- return new String[]{GIT, "push", "-u", "origin", "main"};
- }
-
- /**
- * Performs the following git commands at the repo level:
- *
- * git add .
- * git commit -m {getArg(0)}
- * git push -u origin main
- *
- */
- private static void gitme() {
- if (getInputHandler().noArgs()) {
- getInputHandler().println("gitme usage: gitme [commit message, quotes not needed]");
- return;
- }
-
- String commitMessage = quote + getInputHandler().argsToString() + quote;
- String threadName = "Gitme command, commit message: " + commitMessage;
- CyderThreadRunner.submit(() -> {
- ProcessBuilder gitAddProcessBuilder = new ProcessBuilder(generateGitAddCommand());
-
- String[] GIT_COMMIT_COMMAND = {GIT, "commit", "-m", commitMessage};
- ProcessBuilder gitCommitProcessBuilder = new ProcessBuilder(GIT_COMMIT_COMMAND);
-
- ProcessBuilder gitPushProcessBuilder = new ProcessBuilder(generateGitPushCommand());
-
- ImmutableList builders = ImmutableList.of(
- gitAddProcessBuilder, gitCommitProcessBuilder, gitPushProcessBuilder);
- ProcessUtil.runProcesses(builders).forEach(getInputHandler()::println);
- }, threadName);
- }
-
- /**
- * Prints all the issues found for the official Cyder github repo.
- */
- private static void printIssues() {
- CyderThreadRunner.submit(() -> {
- ImmutableList issues = GitHubUtil.getCyderIssues();
-
- StringBuilder builder = new StringBuilder();
- builder.append(issues.size()).append(space)
- .append(StringUtil.getWordFormBasedOnNumber(issues.size(), "issue"))
- .append(space).append("found:").append(CyderStrings.newline);
- builder.append(issueSeparator).append(CyderStrings.newline);
-
- issues.forEach(issue -> {
- builder.append("Issue #").append(issue.number).append(CyderStrings.newline);
- builder.append(issue.title).append(CyderStrings.newline);
- builder.append(issue.body).append(CyderStrings.newline);
- builder.append(issueSeparator).append(CyderStrings.newline);
- });
-
- getInputHandler().println(builder);
- }, GITHUB_ISSUE_PRINTER_THREAD_NAME);
- }
-}
diff --git a/src/main/java/cyder/handlers/input/GuiTestHandler.java b/src/main/java/cyder/handlers/input/GuiTestHandler.java
deleted file mode 100644
index 8d3e692d8..000000000
--- a/src/main/java/cyder/handlers/input/GuiTestHandler.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.reflect.ClassPath;
-import cyder.annotations.GuiTest;
-import cyder.annotations.Handle;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.strings.CyderStrings;
-import cyder.utils.ReflectionUtil;
-
-import java.lang.reflect.Method;
-
-/**
- * A handler for invoking {@link GuiTest}s.
- */
-public class GuiTestHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private GuiTestHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle
- public static boolean handle() {
- boolean ret = false;
-
- for (ClassPath.ClassInfo classInfo : ReflectionUtil.getCyderClasses()) {
- Class> classer = classInfo.load();
-
- for (Method method : classer.getMethods()) {
- if (method.isAnnotationPresent(GuiTest.class)) {
- String trigger = method.getAnnotation(GuiTest.class).value();
- if (trigger.equalsIgnoreCase(getInputHandler().commandAndArgsToString())) {
- try {
- getInputHandler().println("Invoking gui test " + CyderStrings.quote
- + method.getName() + CyderStrings.quote);
- method.invoke(classer);
- ret = true;
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
- }
- }
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/ImageHandler.java b/src/main/java/cyder/handlers/input/ImageHandler.java
deleted file mode 100644
index a6285241d..000000000
--- a/src/main/java/cyder/handlers/input/ImageHandler.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.user.UserDataManager;
-import cyder.user.UserFile;
-import cyder.utils.ImageUtil;
-import cyder.utils.SecurityUtil;
-import cyder.utils.SpotlightUtil;
-import cyder.utils.StaticUtil;
-
-import javax.swing.*;
-import java.io.File;
-import java.util.Optional;
-import java.util.concurrent.Future;
-
-/**
- * A handler for images and console background manipulation
- */
-public class ImageHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private ImageHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"java", "msu", "nathan", "nate", "html", "css", "docker", "redis", "blur", "unicorn", "spotlight"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().commandIs("java")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("duke.png")));
- } else if (getInputHandler().commandIs("msu")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("msu.png")));
- } else if (getInputHandler().commandIs("nathan") || getInputHandler().commandIs("nate")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("me.png")));
- } else if (getInputHandler().commandIs("html")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("html5.png")));
- } else if (getInputHandler().commandIs("css")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("css.png")));
- } else if (getInputHandler().commandIs("docker")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("Docker.png")));
- } else if (getInputHandler().commandIs("redis")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("Redis.png")));
- } else if (getInputHandler().commandIs("blur")) {
- if (getInputHandler().checkArgsLength(1)) {
- if (ImageUtil.isSolidColor(Console.INSTANCE.getCurrentBackground().generateBufferedImage())) {
- getInputHandler().println("Silly " + UserDataManager.INSTANCE.getUsername()
- + ". Your background is a solid color, bluing that won't do anything :P");
- }
-
- attemptToBlurBackground();
- } else {
- getInputHandler().println("Blur command usage: blur [GAUSSIAN BLUR RADIUS]");
- }
- } else if (getInputHandler().commandIs("unicorn")) {
- getInputHandler().println(new ImageIcon(StaticUtil.getStaticPath("unicorn.png")));
- } else if (getInputHandler().inputIgnoringSpacesMatches("spotlight")) {
- CyderThreadRunner.submit(() -> {
- getInputHandler().println("Saving backgrounds to your backgrounds directory...");
- SpotlightUtil.saveSpotlights(Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(),
- UserFile.BACKGROUNDS.getName()));
- getInputHandler().println("Saved images to your backgrounds directory");
- }, spotlightStealerThreadName);
- } else {
- ret = false;
- }
-
- return ret;
- }
-
- /**
- * The name of the thread which saves the spotlights to the current user's backgrounds directory.
- */
- private static final String spotlightStealerThreadName = "Spotlight Saver";
-
- /**
- * The minimum allowable radius when blurring the background.
- */
- private static final int MIN_BLUR_SIZE = 3;
-
- /**
- * The name of the thread that attempts to blur the current background.
- */
- private static final String BACKGROUND_BLUR_ATTEMPT_THREAD_NAME = "Background Blur Attempt Thread";
-
- /**
- * Attempts to validate a blur command and if valid, blur the current console background.
- */
- private static void attemptToBlurBackground() {
- CyderThreadRunner.submit(() -> {
- try {
- int radius = Integer.parseInt(getInputHandler().getArg(0));
- boolean isEven = radius % 2 == 0;
-
- if (isEven) {
- getInputHandler().println("Blur radius must be an odd number");
- return;
- } else if (radius < MIN_BLUR_SIZE) {
- getInputHandler().println("Minimum blur radius is " + MIN_BLUR_SIZE);
- return;
- }
-
- File currentBackgroundFile = Console.INSTANCE.getCurrentBackground().getReferenceFile();
-
- if (currentBackgroundFile == null || !currentBackgroundFile.exists()) {
- String name = SecurityUtil.generateUuid();
- boolean saved = ImageUtil.saveImageToTemporaryDirectory(Console.INSTANCE
- .getCurrentBackground().generateBufferedImage(), name);
-
- if (!saved) {
- getInputHandler().println("Could not blur background at this time");
- return;
- }
-
- currentBackgroundFile = Dynamic.buildDynamic(
- Dynamic.TEMP.getFileName(), name + Extension.PNG.getExtension());
- }
-
- Future> futureImage = ImageUtil.gaussianBlur(currentBackgroundFile, radius);
- while (!futureImage.isDone()) Thread.onSpinWait();
-
- if (futureImage.get().isPresent()) {
- Console.INSTANCE.setBackgroundFile(futureImage.get().get(), true);
- getInputHandler().println("Background blurred, set, and saved as a separate background file.");
- } else {
- getInputHandler().println("Could not blur background at this time");
- }
- } catch (NumberFormatException ignored) {
- getInputHandler().println("Invalid input for radius: " + getInputHandler().getArg(0));
- } catch (Exception e) {
- getInputHandler().println("Blur command usage: blur [GAUSSIAN BLUR RADIUS]");
- ExceptionHandler.handle(e);
- }
- }, BACKGROUND_BLUR_ATTEMPT_THREAD_NAME);
- }
-}
diff --git a/src/main/java/cyder/handlers/input/InputHandler.java b/src/main/java/cyder/handlers/input/InputHandler.java
deleted file mode 100644
index 128e5fe55..000000000
--- a/src/main/java/cyder/handlers/input/InputHandler.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.console.Console;
-
-/**
- * A base class for InputHandlers to extend in order to enhance readability.
- */
-public abstract class InputHandler {
- /**
- * Returns the Console's input handler.
- *
- * @return the Console's input handler
- */
- protected static BaseInputHandler getInputHandler() {
- return Console.INSTANCE.getInputHandler();
- }
-}
diff --git a/src/main/java/cyder/handlers/input/MathHandler.java b/src/main/java/cyder/handlers/input/MathHandler.java
deleted file mode 100644
index 12b3cad63..000000000
--- a/src/main/java/cyder/handlers/input/MathHandler.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cyder.handlers.input;
-
-import com.fathzer.soft.javaluator.DoubleEvaluator;
-import cyder.annotations.Handle;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-
-/**
- * A handler for handling mathematical expressions.
- */
-public class MathHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private MathHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The evaluator for evaluating mathematical expressions
- */
- private static final DoubleEvaluator evaluator;
-
- static {
- evaluator = new DoubleEvaluator();
- }
-
- @Handle
- public static boolean handle() {
- boolean ret = false;
-
- try {
- double result = evaluator.evaluate(StringUtil.firstCharToLowerCase(
- getInputHandler().commandAndArgsToString()));
- getInputHandler().println(String.valueOf(result));
- ret = true;
- } catch (Exception ignored) {}
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/NetworkHandler.java b/src/main/java/cyder/handlers/input/NetworkHandler.java
deleted file mode 100644
index 7f1812b56..000000000
--- a/src/main/java/cyder/handlers/input/NetworkHandler.java
+++ /dev/null
@@ -1,225 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.constants.CyderRegexPatterns;
-import cyder.constants.CyderUrls;
-import cyder.enumerations.Dynamic;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.network.IpDataManager;
-import cyder.network.NetworkUtil;
-import cyder.network.ScrapingUtil;
-import cyder.props.Props;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.usb.UsbDevice;
-import cyder.usb.UsbUtil;
-import cyder.user.UserFile;
-import cyder.utils.MapUtil;
-import cyder.utils.OsUtil;
-import cyder.utils.SecurityUtil;
-
-import javax.swing.*;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.Future;
-
-/**
- * A handler for things which require internet access and may reach out to external domains for data.
- */
-public class NetworkHandler extends InputHandler {
- /**
- * The name of the waiter thread for getting the usb devices.
- */
- private static final String USB_DEVICE_WAITER_THREAD_NAME = "Usb Device Waiter";
-
- /**
- * The name of the thread for performing the whereami command.
- */
- private static final String WHEREAMI_THREAD_NAME = "Whereami Information Finder";
-
- /**
- * The length of the map shown for the where am i command.
- */
- private static final int WHERE_AM_I_MAP_LENGTH = 200;
-
- /**
- * Suppress default constructor.
- */
- private NetworkHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"define", "wikisum", "ip", "pastebin", "download", "usb", "curl", "whereami", "network devices"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().commandIs("define")) {
- if (!getInputHandler().checkArgsLength(0)) {
- getInputHandler().println(StringUtil.getDefinition(getInputHandler().argsToString()));
- } else {
- getInputHandler().println("define usage: define YOUR_WORD/expression");
- }
- } else if (getInputHandler().commandIs("wikisum")) {
- if (!getInputHandler().checkArgsLength(0)) {
- String wikiSumSearch = getInputHandler().argsToString();
- Optional wikiSumOptional = StringUtil.getWikipediaSummary(wikiSumSearch);
- if (wikiSumOptional.isPresent()) {
- String wikiSum = wikiSumOptional.get();
- getInputHandler().println(wikiSum);
- } else {
- getInputHandler().print("Wikipedia article not found");
- }
- } else {
- getInputHandler().println("wikisum usage: wikisum YOUR_WORD/expression");
- }
- } else if (getInputHandler().commandIs("ip")) {
- String ipDataFoundIp = IpDataManager.INSTANCE.getIpData().getIp();
- getInputHandler().println(Objects.requireNonNullElseGet(ipDataFoundIp,
- () -> NetworkUtil.getIp().orElse("IP not found")));
- } else if (getInputHandler().commandIs("pastebin")) {
- if (getInputHandler().checkArgsLength(1)) {
- String urlString;
- if (getInputHandler().getArg(0).contains("pastebin.com")) {
- urlString = getInputHandler().getArg(0);
- } else {
- urlString = CyderUrls.PASTEBIN_RAW_BASE + getInputHandler().getArg(1);
- }
-
- try {
- URL url = new URL(urlString);
- BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
- String line;
- while ((line = reader.readLine()) != null) {
- getInputHandler().println(line);
- }
-
- reader.close();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- getInputHandler().println("Unknown pastebin url/UUID");
- }
- } else {
- getInputHandler().println("pastebin usage: pastebin [URL/UUID]\nExample: pastebin xa7sJvNm");
- }
- } else if (getInputHandler().commandIs("usb")) {
- CyderThreadRunner.submit(() -> {
- getInputHandler().println("Devices connected to " + OsUtil.getComputerName() + " via USB protocol:");
-
- Future> futureDevices = UsbUtil.getUsbDevices();
- while (!futureDevices.isDone()) Thread.onSpinWait();
-
- try {
- futureDevices.get().forEach(device -> {
- getInputHandler().println("Status: " + device.getStatus());
- getInputHandler().println("Type: " + device.getType());
- getInputHandler().println("Friendly name: " + device.getFriendlyName());
- getInputHandler().println("Instance ID: " + device.getInstanceId());
- getInputHandler().println("-------------------------");
- });
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, USB_DEVICE_WAITER_THREAD_NAME);
- } else if (getInputHandler().commandIs("download")) {
- if (getInputHandler().checkArgsLength(1)) {
- if (NetworkUtil.isValidUrl(getInputHandler().getArg(0))) {
- Optional optionalResponseName = NetworkUtil.getUrlTitle(getInputHandler().getArg(0));
- String saveName = SecurityUtil.generateUuid();
-
- if (optionalResponseName.isPresent()) {
- String responseName = optionalResponseName.get();
- if (!responseName.isEmpty()) {
- saveName = responseName;
- }
- }
-
- File saveFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(), Console.INSTANCE.getUuid(),
- UserFile.FILES.getName(), saveName);
-
- getInputHandler().println("Saving file: " + saveName + " to files directory");
-
- CyderThreadRunner.submit(() -> {
- try {
- if (NetworkUtil.downloadResource(getInputHandler().getArg(0), saveFile)) {
- getInputHandler().println("Successfully saved");
- } else {
- getInputHandler().println("Error: could not download at this time");
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, "File URL Downloader");
- } else {
- getInputHandler().println("Invalid url");
- }
- } else {
- getInputHandler().println("download usage: download [YOUR LINK]");
- }
- } else if (getInputHandler().commandIs("curl")) {
- if (getInputHandler().checkArgsLength(1)) {
- if (NetworkUtil.isValidUrl(getInputHandler().getArg(0))) {
- try {
- URL url = new URL(getInputHandler().getArg(0));
- HttpURLConnection http = (HttpURLConnection) url.openConnection();
-
- getInputHandler().println(NetworkUtil.readUrl(getInputHandler().getArg(0)));
- getInputHandler().println("Response: " + http.getResponseCode()
- + CyderStrings.space + http.getResponseMessage());
-
- http.disconnect();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- } else {
- getInputHandler().println("Invalid url");
- }
- } else {
- getInputHandler().println("Curl command usage: curl [URL]");
- }
- } else if (getInputHandler().inputIgnoringSpacesMatches("whereami")) {
- CyderThreadRunner.submit(() -> {
- ScrapingUtil.IspQueryResult result = ScrapingUtil.getIspAndNetworkDetails();
- getInputHandler().println("You live in " + result.city() + ", " + result.state());
- getInputHandler().println("Your country is: " + result.country());
- getInputHandler().println("Your ip is: " + result.ip());
- getInputHandler().println("Your isp is: " + result.isp());
- getInputHandler().println("Your hostname is: " + result.hostname());
-
- MapUtil.Builder builder = new MapUtil.Builder(WHERE_AM_I_MAP_LENGTH, WHERE_AM_I_MAP_LENGTH,
- Props.mapQuestApiKey.getValue());
- builder.setScaleBar(false);
- builder.setLocationString(result.city()
- .replaceAll(CyderRegexPatterns.whiteSpaceRegex, NetworkUtil.URL_SPACE) + ","
- + result.state().replaceAll(CyderRegexPatterns.whiteSpaceRegex, NetworkUtil.URL_SPACE) + ","
- + result.country().replaceAll(CyderRegexPatterns.whiteSpaceRegex, NetworkUtil.URL_SPACE));
- builder.setZoomLevel(8);
- builder.setFilterWaterMark(true);
-
- try {
- ImageIcon icon = MapUtil.getMapView(builder);
- getInputHandler().println(icon);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, WHEREAMI_THREAD_NAME);
- } else if (getInputHandler().inputIgnoringSpacesMatches("networkdevices")) {
- OsUtil.getNetworkDevices().forEach(networkDevice -> {
- getInputHandler().println("Name: " + networkDevice.name());
- getInputHandler().println("Display name: " + networkDevice.displayName());
- });
- } else {
- ret = false;
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/NumberHandler.java b/src/main/java/cyder/handlers/input/NumberHandler.java
deleted file mode 100644
index 2dbcf1813..000000000
--- a/src/main/java/cyder/handlers/input/NumberHandler.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.constants.CyderRegexPatterns;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.math.NumberToWordUtil;
-import cyder.math.NumberUtil;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-
-/**
- * A handler to handle things involving numbers.
- */
-public class NumberHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private NumberHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"binary", "prime", "bindump", "hexdump", "number2string"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().commandIs("binary")) {
- if (getInputHandler().checkArgsLength(1)
- && CyderRegexPatterns.numberPattern.matcher(getInputHandler().getArg(0)).matches()) {
- CyderThreadRunner.submit(() -> {
- try {
- getInputHandler().println(getInputHandler().getArg(0) + " converted to binary equals: "
- + Integer.toBinaryString(Integer.parseInt(getInputHandler().getArg(0))));
- } catch (Exception ignored) {
- }
- }, "Binary Converter");
- } else {
- getInputHandler().println("Your value must only contain numbers.");
- }
- } else if (getInputHandler().commandIs("prime")) {
- if (getInputHandler().checkArgsLength(1)) {
- int num = Integer.parseInt(getInputHandler().getArg(0));
-
- if (NumberUtil.isPrime(num)) {
- getInputHandler().println(num + " is a prime");
- } else {
- getInputHandler().println(num + " is not a prime because it is divisible by:\n[");
-
- for (int factor : NumberUtil.primeFactors(num)) {
- getInputHandler().println(factor + ", ");
- }
-
- getInputHandler().println(CyderStrings.closingBracket);
- }
- } else {
- getInputHandler().println("Prime usage: prime NUMBER");
- }
- } else if (getInputHandler().commandIs("bindump")) {
- if (getInputHandler().checkArgsLength(2)) {
- if (!getInputHandler().getArg(0).equals("-f")) {
- getInputHandler().println("Bindump usage: bindump -f /path/to/binary/file");
- } else {
- File f = new File(getInputHandler().getArg(1));
-
- if (f.exists()) {
- getInputHandler().printlnPriority("0b" + FileUtil.getBinaryString(f));
- } else {
- getInputHandler().println("File: " + getInputHandler().getArg(0) + " does not exist.");
- }
- }
- } else {
- getInputHandler().println("Bindump usage: bindump -f /path/to/binary/file");
- }
- } else if (getInputHandler().commandIs("hexdump")) {
- if (getInputHandler().checkArgsLength(2)) {
- if (!getInputHandler().getArg(0).equals("-f")) {
- getInputHandler().println("Hexdump usage: hexdump -f /path/to/binary/file");
- } else {
- File f = new File(getInputHandler().getArg(1));
-
- if (!f.exists())
- throw new IllegalArgumentException("File does not exist");
-
- if (FileUtil.getExtension(f).equalsIgnoreCase(Extension.BIN.getExtension())) {
- if (f.exists()) {
- getInputHandler().printlnPriority("0x" + FileUtil.getHexString(f).toUpperCase());
- } else {
- getInputHandler().println("File: " + getInputHandler().getArg(1) + " does not exist.");
- }
- } else {
- try {
- InputStream inputStream = new FileInputStream(f);
- int numberOfColumns = 10;
-
- StringBuilder sb = new StringBuilder();
-
- long streamPtr = 0;
- while (inputStream.available() > 0) {
- long col = streamPtr++ % numberOfColumns;
- sb.append(String.format("%02x ", inputStream.read()));
- if (col == (numberOfColumns - 1)) {
- sb.append(CyderStrings.newline);
- }
- }
-
- inputStream.close();
-
- getInputHandler().printlnPriority(sb.toString());
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
- }
- } else {
- getInputHandler().println("Hexdump usage: hexdump -f /path/to/binary/file");
- }
- } else if (getInputHandler().commandIs("number2string")
- || getInputHandler().commandIs("number2word")) {
- if (getInputHandler().checkArgsLength(1)) {
- if (CyderRegexPatterns.numberPattern.matcher(getInputHandler().getArg(0)).matches()) {
- getInputHandler().println(NumberToWordUtil.toWords(getInputHandler().getArg(0)));
- } else {
- getInputHandler().println("Could not parse input as number: "
- + getInputHandler().getArg(0));
- }
- } else {
- getInputHandler().println("Command usage: number2string [integer]");
- }
- } else {
- ret = false;
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/PixelationHandler.java b/src/main/java/cyder/handlers/input/PixelationHandler.java
deleted file mode 100644
index 3ba7e6287..000000000
--- a/src/main/java/cyder/handlers/input/PixelationHandler.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.collect.Range;
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.user.UserDataManager;
-import cyder.user.UserFile;
-import cyder.utils.ImageUtil;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.File;
-
-/**
- * A handler for handling when images or the console background should be pixelated.
- */
-public class PixelationHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private PixelationHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The range of allowable user-entered pixelation values.
- */
- private static final Range pixelRange = Range.closed(2, 500);
-
- @Handle({"pixelate", "pixelation"})
- public static boolean handle() {
- switch (getInputHandler().getHandleIterations()) {
- case 0 -> {
- boolean isSolidColor = false;
-
- try {
- isSolidColor = ImageUtil.isSolidColor(Console.INSTANCE.getCurrentBackground().getReferenceFile());
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- if (isSolidColor) {
- getInputHandler().println("Silly " + UserDataManager.INSTANCE.getUsername()
- + "; your background " + "is a solid color :P");
- } else {
- if (getInputHandler().checkArgsLength(1)) {
- try {
- int size = Integer.parseInt(getInputHandler().getArg(0));
- attemptPixelation(size);
- } catch (Exception e) {
- return false;
- }
- } else {
- getInputHandler().setRedirectionHandler(PixelationHandler.class);
- getInputHandler().setHandleIterations(1);
- getInputHandler().println("Enter pixel size");
- }
- }
-
- return true;
- }
- case 1 -> {
- try {
- int size = Integer.parseInt(getInputHandler().getCommand());
- attemptPixelation(size);
- } catch (Exception ignored) {
- getInputHandler().println("Could not parse input as an integer");
- }
-
- return true;
- }
- default -> throw new IllegalArgumentException("Illegal handle index for pixelation handler");
- }
- }
-
- /**
- * Attempts to pixelate the Console background if the provided size is within the allowable range.
- *
- * @param size the requested pixel size
- */
- private static void attemptPixelation(int size) {
- if (pixelRange.contains(size)) {
- CyderThreadRunner.submit(() -> {
- try {
- BufferedImage img = ImageUtil.pixelateImage(ImageUtil.read(Console.INSTANCE.
- getCurrentBackground().getReferenceFile().getAbsoluteFile()), size);
-
- String newName = FileUtil.getFilename(Console.INSTANCE
- .getCurrentBackground().getReferenceFile().getName())
- + "_Pixelated_Pixel_Size_" + size + Extension.PNG.getExtension();
-
- File saveFile = Dynamic.buildDynamic(
- Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(),
- UserFile.BACKGROUNDS.getName(), newName);
-
- ImageIO.write(img, Extension.PNG.getExtensionWithoutPeriod(), saveFile);
-
- getInputHandler().println("Background pixelated and saved as a separate background file.");
-
- Console.INSTANCE.setBackgroundFile(saveFile);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, "Console Background Pixelator");
- } else {
- getInputHandler().println("Sorry, " + UserDataManager.INSTANCE.getUsername()
- + ", but your pixel value must be in the range ["
- + pixelRange.lowerEndpoint() + ", " + pixelRange.upperEndpoint() + CyderStrings.closingBracket);
- }
-
- getInputHandler().resetHandlers();
- }
-}
diff --git a/src/main/java/cyder/handlers/input/PlayAudioHandler.java b/src/main/java/cyder/handlers/input/PlayAudioHandler.java
deleted file mode 100644
index b4deee214..000000000
--- a/src/main/java/cyder/handlers/input/PlayAudioHandler.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.audio.CPlayer;
-import cyder.audio.GeneralAudioPlayer;
-import cyder.console.Console;
-import cyder.constants.CyderFonts;
-import cyder.constants.CyderIcons;
-import cyder.constants.CyderUrls;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.managers.RobotManager;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.BletchyAnimationManager;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.utils.StaticUtil;
-import cyder.youtube.YouTubeUtil;
-
-import java.awt.*;
-import java.awt.event.KeyEvent;
-import java.io.File;
-import java.util.concurrent.Future;
-
-/**
- * A handler for commands that play audio.
- */
-public class PlayAudioHandler extends InputHandler {
- /**
- * The all the stars music file.
- */
- private static final File allTheStars = StaticUtil.getStaticResource("allthestars.mp3");
-
- /**
- * The Beyno font.
- */
- private static final Font beynoFont = new CyderFonts.FontBuilder("BEYNO")
- .setSize(getInputHandler().getJTextPane().getFont().getSize()).generate();
-
- /**
- * The chadwick boseman bletchy text.
- */
- private static final String chadwickBosemanBletchyText = "RIP CHADWICK BOSEMAN";
-
- /**
- * The delay between starting the chadwick boseman easter egg audio/bletchy thread,
- * and resetting to the user's font.
- */
- private static final int chadwickBosemanResetFontDelay = 4000;
-
- /**
- * Suppress default constructor.
- */
- private PlayAudioHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"heyya",
- "windows",
- "lightsaber",
- "xbox",
- "startrek",
- "toystory",
- "logic",
- "18002738255",
- "x",
- "black panther",
- "chadwick boseman",
- "f17",
- "play"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().inputIgnoringSpacesMatches("heyya")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("hey.mp3"));
- } else if (getInputHandler().commandIs("windows")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("windows.mp3"));
- } else if (getInputHandler().commandIs("lightsaber")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("lightsaber.mp3"));
- } else if (getInputHandler().commandIs("xbox")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("xbox.mp3"));
- } else if (getInputHandler().commandIs("startrek")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("startrek.mp3"));
- } else if (getInputHandler().commandIs("toystory")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("theclaw.mp3"));
- } else if (getInputHandler().commandIs("logic")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("commando.mp3"));
- } else if (getInputHandler().getCommand().replace(CyderStrings.dash, "").equals("18002738255")) {
- GeneralAudioPlayer.playAudio(StaticUtil.getStaticResource("1800.mp3"));
- } else if (getInputHandler().commandIs(CyderStrings.X)) {
- Console.INSTANCE.getConsoleCyderFrame().setIconImage(CyderIcons.X_ICON.getImage());
- File audioFile = StaticUtil.getStaticResource("x.mp3");
- GeneralAudioPlayer.playAudio(new CPlayer(audioFile).addOnCompletionCallback(
- () -> Console.INSTANCE.getConsoleCyderFrame().setIconImage(CyderIcons.CYDER_ICON.getImage())));
- } else if (getInputHandler().inputIgnoringSpacesMatches("black panther")
- || getInputHandler().inputIgnoringSpacesMatches("chadwick boseman")) {
- chadwickBosemanEasterEgg();
- } else if (getInputHandler().commandIs("f17")) {
- if (RobotManager.INSTANCE.getRobot() != null) {
- RobotManager.INSTANCE.getRobot().keyPress(KeyEvent.VK_F17);
- } else {
- getInputHandler().println("Mr. Robot didn't start :(");
- }
- } else if (getInputHandler().commandIs("play")) {
- onPlayCommand();
- } else {
- ret = false;
- }
-
- return ret;
- }
-
- /**
- * The actions to invoke when a play command is handled.
- */
- private static void onPlayCommand() {
- if (StringUtil.isNullOrEmpty(getInputHandler().argsToString())) {
- getInputHandler().println("Play command usage: Play [video_url/playlist_url/search query]");
- }
-
- CyderThreadRunner.submit(() -> {
- String url = getInputHandler().argsToString();
-
- if (YouTubeUtil.isPlaylistUrl(url)) {
- // todo we can either extract all uuids and download individually or simply let youtube-ld
- // handle downloading them all
- } else if (YouTubeUtil.isVideoUrl(url)) {
- YouTubeUtil.downloadYouTubeAudio(url, Console.INSTANCE.getInputHandler());
- } else {
- getInputHandler().println("Searching YouTube for: " + url);
-
- try {
- Future futureUuid = YouTubeUtil.getMostLikelyUuid(url);
- while (!futureUuid.isDone()) Thread.onSpinWait();
- url = CyderUrls.YOUTUBE_VIDEO_HEADER + futureUuid.get();
- YouTubeUtil.downloadYouTubeAudio(url, Console.INSTANCE.getInputHandler());
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
- }, "YouTube Download Initializer");
- }
-
- /**
- * Shows the Chadwick Boseman easter egg.
- */
- private static void chadwickBosemanEasterEgg() {
- String threadName = "Chadwick Boseman Easter Egg Thread";
- CyderThreadRunner.submit(() -> {
- getInputHandler().getJTextPane().setText("");
-
- GeneralAudioPlayer.playAudio(allTheStars);
- getInputHandler().getJTextPane().setFont(beynoFont);
- BletchyAnimationManager.INSTANCE.bletchy(
- chadwickBosemanBletchyText, false, 15, false);
-
- ThreadUtil.sleep(chadwickBosemanResetFontDelay);
-
- getInputHandler().getJTextPane().setFont(Console.INSTANCE.generateUserFont());
- }, threadName);
- }
-}
diff --git a/src/main/java/cyder/handlers/input/PropHandler.java b/src/main/java/cyder/handlers/input/PropHandler.java
deleted file mode 100644
index 8fcbab95d..000000000
--- a/src/main/java/cyder/handlers/input/PropHandler.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.exceptions.IllegalMethodException;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.props.PropLoader;
-import cyder.props.Props;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-
-/**
- * A handler for utilities related to props.
- */
-public class PropHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private PropHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle("reload props")
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().inputIgnoringSpacesMatches("reloadprops")) {
- if (!Props.propsReloadable.getValue()) {
- getInputHandler().println("Reloading props is currently disabled"
- + " during runtime, check your props file");
- } else {
- Logger.log(LogTag.PROPS_ACTION, "Reloading props");
- PropLoader.reloadProps();
- Logger.log(LogTag.PROPS_ACTION, "Props reloaded");
- int size = PropLoader.getPropsSize();
- getInputHandler().println("Reloaded " + size + " "
- + StringUtil.getWordFormBasedOnNumber(size, "prop"));
- }
- } else ret = false;
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/StatHandler.java b/src/main/java/cyder/handlers/input/StatHandler.java
deleted file mode 100644
index 422f585fe..000000000
--- a/src/main/java/cyder/handlers/input/StatHandler.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.reflect.ClassPath;
-import cyder.annotations.GuiTest;
-import cyder.annotations.Handle;
-import cyder.annotations.Widget;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.enumerations.SystemPropertyKey;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.utils.OsUtil;
-import cyder.utils.ReflectionUtil;
-import cyder.utils.StatUtil;
-
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.concurrent.Future;
-
-/**
- * A handler for finding and printing statistics.
- */
-public class StatHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private StatHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"debug", "count logs", "computer properties", "system properties", "tests",
- "network addresses", "filesizes", "badwords", "widgets", "analyze code", "java properties",
- "threads", "daemon threads"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().commandIs("debug")) {
- CyderThreadRunner.submit(() -> {
- try {
- getInputHandler().println("Querying computer memory...");
- ImmutableList memory = StatUtil.getComputerMemorySpaces();
- getInputHandler().println("Computer memory:");
- for (String prop : memory) {
- getInputHandler().println(prop);
- }
-
- getInputHandler().println("Java properties:");
- Arrays.stream(SystemPropertyKey.values()).forEach(propertyKey
- -> getInputHandler().println(propertyKey.getProperty()));
-
- getInputHandler().println("System properties:");
- for (String prop : StatUtil.getSystemProperties()) {
- getInputHandler().println(prop);
- }
-
- Future futureStats = StatUtil.getDebugProps();
- while (!futureStats.isDone()) Thread.onSpinWait();
- StatUtil.DebugStats stats = futureStats.get();
-
- getInputHandler().println("Debug stats:");
- for (String line : stats.lines()) {
- getInputHandler().println(line);
- }
-
- getInputHandler().println("Country flag:");
- getInputHandler().println(stats.countryFlag());
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, "Debug Stat Finder");
- } else if (getInputHandler().inputIgnoringSpacesMatches("computerproperties")) {
- getInputHandler().println("This may take a second since this feature counts your PC's free memory");
-
- CyderThreadRunner.submit(() -> {
- for (String prop : StatUtil.getComputerMemorySpaces()) {
- getInputHandler().println(prop);
- }
- }, "Computer Memory Computer");
- } else if (getInputHandler().inputIgnoringSpacesMatches("systemproperties")) {
- for (String prop : StatUtil.getSystemProperties()) {
- getInputHandler().println(prop);
- }
- } else if (getInputHandler().commandIs("countlogs")) {
- File[] logDirs = Dynamic.buildDynamic(Dynamic.LOGS.getFileName()).listFiles();
- int count = 0;
- int days = 0;
-
- if (logDirs != null && logDirs.length > 0) {
- for (File logDir : logDirs) {
- days++;
-
- File[] logDirFiles = logDir.listFiles();
-
- if (logDirFiles != null && logDirFiles.length > 0) {
- for (File log : logDirFiles) {
- if (FileUtil.getExtension(log).equals(Extension.LOG.getExtension())
- && !logDir.equals(Logger.getCurrentLogFile())) {
- count++;
- }
- }
- }
- }
- }
-
- getInputHandler().println("Number of log dirs: " + days);
- getInputHandler().println("Number of logs: " + count);
- } else if (getInputHandler().commandIs("tests")) {
- getInputHandler().println("Valid GUI tests to call:");
- getInputHandler().printlns(getGuiTestTriggers());
- } else if (getInputHandler().inputIgnoringSpacesMatches("networkaddresses")) {
- try {
- Enumeration nets = NetworkInterface.getNetworkInterfaces();
-
- for (NetworkInterface netInterface : Collections.list(nets)) {
- getInputHandler().println("Display name: " + netInterface.getDisplayName());
- getInputHandler().println("Name: " + netInterface.getName());
-
- Enumeration inetAddresses = netInterface.getInetAddresses();
- for (InetAddress inetAddress : Collections.list(inetAddresses)) {
- getInputHandler().println("InetAddress: " + inetAddress);
- }
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- } else if (getInputHandler().inputIgnoringSpacesMatches("filesizes")) {
- for (StatUtil.FileSize fileSize : StatUtil.fileSizes()) {
- getInputHandler().println(fileSize.name() + ": " + OsUtil.formatBytes(fileSize.size()));
- }
- } else if (getInputHandler().commandIs("widgets")) {
- ArrayList descriptions = getWidgetDescriptions();
-
- getInputHandler().println("Found " + descriptions.size() + " widgets:");
- getInputHandler().println("-------------------------------------");
-
- for (WidgetDescription description : descriptions) {
- StringBuilder triggers = new StringBuilder();
-
- for (int i = 0 ; i < description.triggers().length ; i++) {
- triggers.append(description.triggers()[i]);
-
- if (i != description.triggers().length - 1)
- triggers.append(", ");
- }
-
- getInputHandler().println("Name: " + description.name());
- getInputHandler().println("Description: " + description.description() + "\nTriggers: ["
- + triggers.toString().trim() + CyderStrings.closingBracket);
- getInputHandler().println("-------------------------------------");
- }
- } else if (getInputHandler().inputIgnoringSpacesMatches("analyzecode")) {
- if (OsUtil.JAR_MODE) {
- getInputHandler().println("Code analyzing is not available when in Jar mode");
- } else {
- if (getInputHandler().checkArgsLength(0)
- || getInputHandler().checkArgsLength(1)) {
- File startDir = new File("src");
-
- if (getInputHandler().checkArgsLength(1)) {
- startDir = new File(getInputHandler().getArg(0));
-
- if (!startDir.exists()) {
- getInputHandler().println("Invalid root directory");
- startDir = new File("src/main/java/cyder");
- }
- }
-
- File finalStartDir = startDir;
-
- CyderThreadRunner.submit(() -> {
- int codeLines = StatUtil.totalJavaLines(finalStartDir);
- int commentLines = StatUtil.totalComments(finalStartDir);
-
- getInputHandler().println("Total lines: " + StatUtil.totalLines(finalStartDir));
- getInputHandler().println("Code lines: " + codeLines);
- getInputHandler().println("Blank lines: " + StatUtil.totalBlankLines(finalStartDir));
- getInputHandler().println("Comment lines: " + commentLines);
- getInputHandler().println("Classes: " + ReflectionUtil.getCyderClasses().size());
-
- float ratio = ((float) codeLines / (float) commentLines);
- getInputHandler().println("Code to comment ratio: "
- + new DecimalFormat("#0.00").format(ratio));
- }, "Code Analyzer");
- } else {
- getInputHandler().println("analyzecode usage: analyzecode [path/to/the/root/directory] " +
- "(leave path blank to analyze Cyder)");
- }
- }
- } else if (getInputHandler().inputIgnoringSpacesMatches("javaproperties")) {
- Arrays.stream(SystemPropertyKey.values()).forEach(propertyKey
- -> getInputHandler().println(propertyKey.getProperty()));
- } else if (getInputHandler().commandIs("threads")) {
- getInputHandler().printlns(ThreadUtil.getThreadNames());
- } else if (getInputHandler().inputIgnoringSpacesMatches("daemonthreads")) {
- getInputHandler().printlns(ThreadUtil.getDaemonThreadNames());
- } else {
- ret = false;
- }
-
- return ret;
- }
-
- /**
- * A widget and its properties.
- */
- private record WidgetDescription(String name, String description, String[] triggers) {}
-
- /**
- * Returns a list of names, descriptions, and triggers of all the widgets found within Cyder.
- *
- * @return a list of descriptions of all the widgets found within Cyder
- */
- private static ArrayList getWidgetDescriptions() {
- ArrayList ret = new ArrayList<>();
-
- for (ClassPath.ClassInfo classInfo : ReflectionUtil.getCyderClasses()) {
- Class> clazz = classInfo.load();
-
- for (Method method : clazz.getMethods()) {
- if (method.isAnnotationPresent(Widget.class)) {
- String[] triggers = method.getAnnotation(Widget.class).triggers();
- String description = method.getAnnotation(Widget.class).description();
- ret.add(new WidgetDescription(clazz.getName(), description, triggers));
- }
- }
- }
-
- return ret;
- }
-
- /**
- * Returns a list of valid gui triggers exposed in Cyder.
- *
- * @return a list of triggers for gui tests
- */
- private static ImmutableList getGuiTestTriggers() {
- ArrayList ret = new ArrayList<>();
-
- for (ClassPath.ClassInfo classInfo : ReflectionUtil.getCyderClasses()) {
- Class> clazz = classInfo.load();
-
- for (Method m : clazz.getMethods()) {
- if (m.isAnnotationPresent(GuiTest.class)) {
- String trigger = m.getAnnotation(GuiTest.class).value();
- ret.add(trigger);
- }
- }
- }
-
- return ImmutableList.copyOf(ret);
- }
-}
diff --git a/src/main/java/cyder/handlers/input/TestHandler.java b/src/main/java/cyder/handlers/input/TestHandler.java
deleted file mode 100644
index 2cc4889fb..000000000
--- a/src/main/java/cyder/handlers/input/TestHandler.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.base.Preconditions;
-import com.google.common.reflect.ClassPath;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import cyder.annotations.CyderTest;
-import cyder.annotations.Handle;
-import cyder.exceptions.FatalException;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.utils.ReflectionUtil;
-
-import java.lang.reflect.Method;
-
-/**
- * A handler for invoking {@link cyder.annotations.CyderTest}s.
- */
-public class TestHandler extends InputHandler {
- /**
- * The name of the default parameter.
- */
- private static final String VALUE = "value";
-
- /**
- * Suppress default constructor.
- */
- private TestHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * Invokes all tests with the default trigger of {@link #VALUE}.
- */
- public static void invokeDefaultTests() {
- Class> clazz = CyderTest.class;
-
- Method method = null;
- try {
- method = clazz.getDeclaredMethod(VALUE);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- if (method == null) {
- throw new FatalException("Failed reflection when attempting to find CyderTest's default value");
- }
- String value = (String) method.getDefaultValue();
- invokeTestsWithTrigger(value);
- }
-
- @Handle
- public static boolean handle() {
- boolean testTriggered = false;
-
- for (ClassPath.ClassInfo classInfo : ReflectionUtil.getCyderClasses()) {
- Class> classer = classInfo.load();
-
- for (Method method : classer.getMethods()) {
- if (method.isAnnotationPresent(CyderTest.class)) {
- String trigger = method.getAnnotation(CyderTest.class).value();
- if (!trigger.equalsIgnoreCase(getInputHandler().commandAndArgsToString())) continue;
- testTriggered = invokeTestsWithTrigger(trigger);
- if (testTriggered) break;
- }
- }
- }
-
- return testTriggered;
- }
-
- /**
- * Invokes any and all {@link CyderTest}s found with the provided trigger.
- *
- * @param trigger the trigger
- * @return whether a test was invoked
- */
- @CanIgnoreReturnValue
- private static boolean invokeTestsWithTrigger(String trigger) {
- Preconditions.checkNotNull(trigger);
- Preconditions.checkArgument(!trigger.isEmpty());
-
- boolean ret = false;
-
- for (ClassPath.ClassInfo classInfo : ReflectionUtil.getCyderClasses()) {
- Class> classer = classInfo.load();
-
- for (Method method : classer.getMethods()) {
- if (method.isAnnotationPresent(CyderTest.class)) {
- if (!ReflectionUtil.isStatic(method)) {
- Logger.log(LogTag.CYDER_TEST_WARNING, "CyderTest method"
- + " found not static: " + method.getName());
- continue;
- }
- if (!ReflectionUtil.isPublic(method)) {
- Logger.log(LogTag.CYDER_TEST_WARNING, "CyderTest method"
- + " found not public: " + method.getName());
- continue;
- }
- if (!ReflectionUtil.returnsVoid(method)) {
- Logger.log(LogTag.CYDER_TEST_WARNING, "CyderTest method"
- + " found not void return: " + method.getName());
- continue;
- }
-
- String testTrigger = method.getAnnotation(CyderTest.class).value();
- if (trigger.equalsIgnoreCase(testTrigger)) {
- String threadName = "CyderTest thread runner, method: " + CyderStrings.quote
- + method.getName() + CyderStrings.quote;
- CyderThreadRunner.submit(() -> {
- try {
- Logger.log(LogTag.DEBUG, "Invoking CyderTest "
- + CyderStrings.quote + method.getName() + CyderStrings.quote
- + " in " + ReflectionUtil.getBottomLevelClass(classer));
- method.invoke(classer);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, threadName);
-
- ret = true;
- }
- }
- }
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/ThreadHandler.java b/src/main/java/cyder/handlers/input/ThreadHandler.java
deleted file mode 100644
index a5cbaa8a9..000000000
--- a/src/main/java/cyder/handlers/input/ThreadHandler.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.audio.GeneralAudioPlayer;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.threads.YoutubeUuidCheckerManager;
-
-/**
- * A handler to handle things related to thread ops.
- */
-public class ThreadHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private ThreadHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"random youtube", "stop script", "stop music"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().inputIgnoringSpacesMatches("randomyoutube")) {
- YoutubeUuidCheckerManager.INSTANCE.start(1);
- } else if (getInputHandler().inputIgnoringSpacesMatches("stopscript")) {
- YoutubeUuidCheckerManager.INSTANCE.killAll();
- getInputHandler().println("YouTube scripts have been killed.");
- } else if (getInputHandler().inputIgnoringSpacesMatches("stopmusic")) {
- GeneralAudioPlayer.stopGeneralAudio();
- } else {
- ret = false;
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/UiHandler.java b/src/main/java/cyder/handlers/input/UiHandler.java
deleted file mode 100644
index 691c005c9..000000000
--- a/src/main/java/cyder/handlers/input/UiHandler.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.Handle;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.enumerations.ExitCondition;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.ui.UiUtil;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.slider.CyderSliderUi;
-import cyder.ui.slider.ThumbShape;
-import cyder.user.UserDataManager;
-import cyder.user.creation.UserCreator;
-import cyder.utils.OsUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.datatransfer.StringSelection;
-import java.util.stream.IntStream;
-
-/**
- * A handler for handling things related to the ui and painting.
- */
-public class UiHandler extends InputHandler {
- /**
- * The slider used to change the opacity of the Console.
- */
- private static JSlider opacitySlider;
-
- /**
- * Suppress default constructor.
- */
- private UiHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle({"toast", "opacity", "original chams", "screenshot frames", "monitors",
- "create user", "panic", "quit", "logout", "clear clipboard", "mouse", "frames", "freeze"})
- public static boolean handle() {
- boolean ret = true;
-
- if (getInputHandler().commandIs("toast")) {
- Console.INSTANCE.getConsoleCyderFrame().toast("A toast to you, my liege");
- } else if (getInputHandler().commandIs("freeze")) {
- //noinspection StatementWithEmptyBody
- while (true) {}
- } else if (getInputHandler().commandIs("opacity")) {
- if (opacitySlider == null) initializeOpacitySlider();
- getInputHandler().println(opacitySlider);
- } else if (getInputHandler().inputIgnoringSpacesMatches("original chams")) {
- Console.INSTANCE.originalChams();
- } else if (getInputHandler().inputIgnoringSpacesMatches("screenshot frames")) {
- UiUtil.screenshotCyderFrames();
- getInputHandler().println("Successfully saved to your Files directory");
- } else if (getInputHandler().commandIs("monitors")) {
- StringBuilder printString = new StringBuilder("Monitor display modes: ").append(CyderStrings.newline);
- ImmutableList modes = UiUtil.getMonitorDisplayModes();
- IntStream.range(0, modes.size()).forEach(index -> {
- printString.append("Mode ").append(index + 1).append(CyderStrings.newline);
-
- DisplayMode displayMode = modes.get(index);
- printString.append("Width: ").append(displayMode.getWidth()).append(CyderStrings.newline);
- printString.append("Height: ").append(displayMode.getHeight()).append(CyderStrings.newline);
- printString.append("Bit depth: ").append(displayMode.getBitDepth()).append(CyderStrings.newline);
- printString.append("Refresh rate: ").append(displayMode.getRefreshRate()).append(CyderStrings.newline);
- });
-
- getInputHandler().println(printString.toString().trim());
- } else if (getInputHandler().inputIgnoringSpacesMatches("create user")) {
- UserCreator.showGui();
- } else if (getInputHandler().commandIs("panic")) {
- if (UserDataManager.INSTANCE.shouldMinimizeOnClose()) {
- UiUtil.minimizeAllFrames();
- } else {
- OsUtil.exit(ExitCondition.StandardControlledExit);
- }
- } else if (getInputHandler().commandIs("quit")
- || getInputHandler().commandIs("exit")
- || getInputHandler().commandIs("leave")
- || getInputHandler().commandIs("close")) {
- if (UserDataManager.INSTANCE.shouldMinimizeOnClose()) {
- UiUtil.minimizeAllFrames();
- } else {
- Console.INSTANCE.releaseResourcesAndCloseFrame(true);
- }
- } else if (getInputHandler().commandIs("logout")) {
- Console.INSTANCE.logoutCurrentUserAndShowLoginFrame();
- } else if (getInputHandler().commandIs("mouse")) {
- if (getInputHandler().checkArgsLength(2)) {
- OsUtil.setMouseLocation(Integer.parseInt(getInputHandler().getArg(0)),
- Integer.parseInt(getInputHandler().getArg(1)));
- } else {
- getInputHandler().println("Mouse command usage: mouse xPixelLocation, yPixelLocation");
- }
- } else if (getInputHandler().inputIgnoringSpacesMatches("clear clipboard")) {
- StringSelection selection = new StringSelection(null);
- java.awt.datatransfer.Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- clipboard.setContents(selection, selection);
- getInputHandler().println("Clipboard has been reset.");
- } else if (getInputHandler().commandIs("frames")) {
- for (CyderFrame frame : UiUtil.getCyderFrames()) {
- getInputHandler().println(frame);
- }
- } else {
- ret = false;
- }
-
- return ret;
- }
-
- /**
- * Sets up the opacity slider.
- */
- private static void initializeOpacitySlider() {
- opacitySlider = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 100);
- opacitySlider.setBounds(0, 0, 300, 50);
- CyderSliderUi ui = new CyderSliderUi(opacitySlider);
- ui.setThumbStroke(new BasicStroke(2.0f));
- ui.setThumbShape(ThumbShape.CIRCLE);
- ui.setThumbRadius(35);
- ui.setThumbFillColor(CyderColors.navy);
- ui.setThumbOutlineColor(CyderColors.vanilla);
- ui.setRightThumbColor(CyderColors.vanilla);
- ui.setLeftThumbColor(CyderColors.regularPink);
- ui.setTrackStroke(new BasicStroke(3.0f));
- opacitySlider.setUI(ui);
- opacitySlider.setPaintTicks(false);
- opacitySlider.setPaintLabels(false);
- opacitySlider.setVisible(true);
- opacitySlider.setValue((int) (Console.INSTANCE.getConsoleCyderFrame().getOpacity()
- * opacitySlider.getMaximum()));
- opacitySlider.addChangeListener(e -> {
- float opacity = opacitySlider.getValue() / (float) opacitySlider.getMaximum();
- Console.INSTANCE.getConsoleCyderFrame().setOpacity(opacity);
- opacitySlider.repaint();
- });
- opacitySlider.setOpaque(false);
- opacitySlider.setToolTipText("Opacity");
- opacitySlider.setFocusable(false);
- opacitySlider.repaint();
- }
-}
diff --git a/src/main/java/cyder/handlers/input/UrlHandler.java b/src/main/java/cyder/handlers/input/UrlHandler.java
deleted file mode 100644
index e1e1e9e5d..000000000
--- a/src/main/java/cyder/handlers/input/UrlHandler.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.Handle;
-import cyder.constants.CyderRegexPatterns;
-import cyder.constants.CyderUrls;
-import cyder.exceptions.IllegalMethodException;
-import cyder.network.NetworkUtil;
-import cyder.strings.CyderStrings;
-
-import java.net.URL;
-
-/**
- * A handler for opening urls.
- */
-public class UrlHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private UrlHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The YouTube base url for searching for specific words within a YouTube url.
- */
- public static final String YOUTUBE_WORD_SEARCH_BASE =
- "https://www.google.com/search?q=allinurl:REPLACE site:youtube.com";
-
- /**
- * A record to link a trigger to a url and the printable version name.
- */
- private record CyderUrl(String trigger, String url, String printable) {}
-
- /**
- * The list of urls to search trough before attempting to open the raw user input.
- */
- private static final ImmutableList urls = ImmutableList.of(
- new CyderUrl("desmos", CyderUrls.DESMOS, "Opening Desmos graphing calculator"),
- new CyderUrl("404", CyderUrls.GOOGLE_404, "Opening a 404 error"),
- new CyderUrl("coffee", CyderUrls.COFFEE_SHOPS, "Finding coffee shops near you"),
- new CyderUrl("quake3", CyderUrls.QUAKE_3,
- "Opening a video about the Quake 3 fast inverse square root algorithm"),
- new CyderUrl("triangle", CyderUrls.TRIANGLE, "Opening triangle calculator"),
- new CyderUrl("board", CyderUrls.FLY_SQUIRREL_FLY_HTML, "Opening a slingshot game"),
- new CyderUrl("arduino", CyderUrls.ARDUINO, "Raspberry pis are better"),
- new CyderUrl("raspberrypi", CyderUrls.RASPBERRY_PI, "Arduinos are better"),
- new CyderUrl("vexento", CyderUrls.VEXENTO, "Opening a great artist"),
- new CyderUrl("papersplease", CyderUrls.PAPERS_PLEASE, "Opening a great game"),
- new CyderUrl("donut", CyderUrls.DUNKIN_DONUTS, "Dunkin' Hoes; the world runs on it"),
- new CyderUrl("bai", CyderUrls.BAI, "The best drink"),
- new CyderUrl("occamsrazor", CyderUrls.OCCAM_RAZOR, "Opening Occam's razor"),
- new CyderUrl("rickandmorty", CyderUrls.PICKLE_RICK,
- "Turned myself into a pickle morty! Boom! Big reveal; I'm a pickle!"),
- new CyderUrl("about:blank", "about:blank", "Opening about:blank")
- );
-
- @Handle
- public static boolean handle() {
- boolean ret = true;
-
- for (CyderUrl url : urls) {
- if (getInputHandler().commandIs(url.trigger())) {
- getInputHandler().println(url.printable());
- NetworkUtil.openUrl(url.url());
- return true;
- }
- }
-
- if (getInputHandler().commandIs("YoutubeWordSearch")) {
- youTubeWordSearch();
- } else {
- String possibleUrl = getInputHandler().commandAndArgsToString();
- if (urlValid(possibleUrl)) {
- NetworkUtil.openUrl(possibleUrl);
- } else {
- ret = false;
- }
- }
-
- return ret;
- }
-
- /**
- * Performs the YouTube word search routine on the user-entered input.
- */
- private static void youTubeWordSearch() {
- if (getInputHandler().checkArgsLength(1)) {
- String input = getInputHandler().getArg(0);
- String browse = YOUTUBE_WORD_SEARCH_BASE
- .replace("REPLACE", input).replace(CyderRegexPatterns.whiteSpaceRegex, "+");
- NetworkUtil.openUrl(browse);
- } else {
- getInputHandler().println("YoutubeWordSearch usage: YoutubeWordSearch WORD_TO_FIND");
- }
- }
-
- /**
- * Returns whether the provided url is valid.
- *
- * @param url the url to validate
- * @return whether the provided url is valid
- */
- private static boolean urlValid(String url) {
- Preconditions.checkNotNull(url);
- Preconditions.checkArgument(!url.isEmpty());
-
- try {
- new URL(url).openConnection();
- return true;
- } catch (Exception ignored) {}
-
- return false;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/UserDataHandler.java b/src/main/java/cyder/handlers/input/UserDataHandler.java
deleted file mode 100644
index d6dac4c70..000000000
--- a/src/main/java/cyder/handlers/input/UserDataHandler.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.annotations.SuppressCyderInspections;
-import cyder.constants.CyderRegexPatterns;
-import cyder.enumerations.CyderInspection;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.user.UserData;
-import cyder.user.UserDataManager;
-import cyder.user.UserEditor;
-import cyder.utils.BooleanUtils;
-
-import java.util.Optional;
-
-/**
- * A handler for switching/toggling user data.
- */
-public class UserDataHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private UserDataHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @SuppressCyderInspections(CyderInspection.HandleInspection)
- @Handle({"userdata-files", "userdata-fonts", "userdata-colors", "userdata-booleans", "userdata-fields"})
- public static boolean handle() {
- if (getInputHandler().inputIgnoringSpacesMatches("userdata-files")) {
- UserEditor.showGui(UserEditor.Page.FILES);
- return true;
- } else if (getInputHandler().inputIgnoringSpacesMatches("userdata-fonts")) {
- UserEditor.showGui(UserEditor.Page.FONT_AND_COLOR);
- return true;
- } else if (getInputHandler().inputIgnoringSpacesMatches("userdata-colors")) {
- UserEditor.showGui(UserEditor.Page.FONT_AND_COLOR);
- return true;
- } else if (getInputHandler().inputIgnoringSpacesMatches("userdata-booleans")) {
- UserEditor.showGui(UserEditor.Page.BOOLEANS);
- return true;
- } else if (getInputHandler().inputIgnoringSpacesMatches("userdata-fields")) {
- UserEditor.showGui(UserEditor.Page.FIELDS);
- return true;
- }
-
- return attemptUserDataToggle();
- }
-
- /**
- * Attempts to find a user data with the user's input and toggle the parity of it.
- *
- * @return whether a user data could be found and toggled
- */
- private static boolean attemptUserDataToggle() {
- String targetedUserData = getInputHandler().getCommand();
- String parsedArgs = getInputHandler().argsToString()
- .replaceAll(CyderRegexPatterns.whiteSpaceRegex, "");
-
- for (UserData> userdata : UserData.getUserDatas()) {
- if (targetedUserData.equalsIgnoreCase(userdata.getId())) {
- if (userdata.getType().equals(Boolean.class) && !userdata.shouldIgnoreForToggleSwitches()) {
- Optional optionalOldValue =
- UserDataManager.INSTANCE.getUserDataById(userdata.getId(), Boolean.class);
- if (optionalOldValue.isEmpty()) return false;
-
- boolean oldValue = optionalOldValue.get();
-
- boolean newValue;
- if (BooleanUtils.isTrue(parsedArgs)) {
- newValue = true;
- } else if (BooleanUtils.isFalse(parsedArgs)) {
- newValue = false;
- } else {
- newValue = !oldValue;
- }
-
- boolean toggled = UserDataManager.INSTANCE.setUserDataById(userdata.getId(), newValue);
- if (toggled) {
- getInputHandler().println(userdata.getId() + " set to " + newValue);
- UserData.invokeRefresh(userdata.getId());
- } else {
- getInputHandler().println("Failed to set " + userdata.getId());
- }
-
- return true;
- }
- }
- }
-
- return false;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/WidgetHandler.java b/src/main/java/cyder/handlers/input/WidgetHandler.java
deleted file mode 100644
index 4786946f8..000000000
--- a/src/main/java/cyder/handlers/input/WidgetHandler.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cyder.handlers.input;
-
-import com.google.common.reflect.ClassPath;
-import cyder.annotations.Handle;
-import cyder.annotations.Widget;
-import cyder.console.Console;
-import cyder.constants.CyderRegexPatterns;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.utils.ReflectionUtil;
-
-import java.lang.reflect.Method;
-
-/**
- * A handler for opening classes tagged as a widget via the @Widget annotation.
- */
-public class WidgetHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private WidgetHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle
- public static boolean handle() {
- for (ClassPath.ClassInfo classInfo : ReflectionUtil.getCyderClasses()) {
- Class> clazz = classInfo.load();
-
- for (Method m : clazz.getMethods()) {
- if (m.isAnnotationPresent(Widget.class)) {
- String[] widgetTriggers = m.getAnnotation(Widget.class).triggers();
-
- for (String widgetTrigger : widgetTriggers) {
- widgetTrigger = widgetTrigger.replaceAll(CyderRegexPatterns.whiteSpaceRegex, "");
- String userInput = getInputHandler().commandAndArgsToString()
- .replaceAll(CyderRegexPatterns.whiteSpaceRegex, "");
-
- if (widgetTrigger.equalsIgnoreCase(userInput)) {
- String shortWidgetName = ReflectionUtil.getBottomLevelClass(clazz);
- Console.INSTANCE.getInputHandler().println("Opening widget: " + shortWidgetName);
- try {
- if (m.getParameterCount() == 0) {
- m.invoke(clazz);
-
- Logger.log(LogTag.WIDGET_OPENED,
- shortWidgetName + ", trigger = " +
- getInputHandler().commandAndArgsToString());
-
- return true;
- } else
- throw new IllegalStateException("Found widget showGui()" +
- " annotated method with parameters: " + m.getName() + ", class: " + clazz);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
- }
- }
- }
- }
-
- return false;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/WrappedCommandHandler.java b/src/main/java/cyder/handlers/input/WrappedCommandHandler.java
deleted file mode 100644
index 2b38f4d46..000000000
--- a/src/main/java/cyder/handlers/input/WrappedCommandHandler.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package cyder.handlers.input;
-
-import cyder.annotations.Handle;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.strings.CyderStrings;
-
-/**
- * A handler for inner commands wrapped with arguments such as size(x), floor(x, y), etc.
- */
-public class WrappedCommandHandler extends InputHandler {
- /**
- * Suppress default constructor.
- */
- private WrappedCommandHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Handle
- public static boolean handle() {
- boolean ret = true;
-
- String command = getInputHandler().commandAndArgsToString();
-
- try {
- int firstParen = command.indexOf(CyderStrings.openingParenthesis);
- int comma = command.indexOf(",");
- int lastParen = command.indexOf(CyderStrings.closingParenthesis);
-
- String operation;
- String param1 = "";
- String param2 = "";
-
- if (firstParen != -1) {
- operation = command.substring(0, firstParen);
-
- if (comma != -1) {
- param1 = command.substring(firstParen + 1, comma);
-
- if (lastParen != -1) {
- param2 = command.substring(comma + 1, lastParen);
- }
- } else if (lastParen != -1) {
- param1 = command.substring(firstParen + 1, lastParen);
- }
-
- if (operation.equalsIgnoreCase("abs")) {
- getInputHandler().println(Math.abs(Double.parseDouble(param1)));
- } else if (operation.equalsIgnoreCase("ceil")) {
- getInputHandler().println(Math.ceil(Double.parseDouble(param1)));
- } else if (operation.equalsIgnoreCase("floor")) {
- getInputHandler().println(Math.floor(Double.parseDouble(param1)));
- } else if (operation.equalsIgnoreCase("log")) {
- getInputHandler().println(Math.log(Double.parseDouble(param1)));
- } else if (operation.equalsIgnoreCase("log10")) {
- getInputHandler().println(Math.log10(Double.parseDouble(param1)));
- } else if (operation.equalsIgnoreCase("max")) {
- getInputHandler().println(Math.max(Double.parseDouble(param1), Double.parseDouble(param2)));
- } else if (operation.equalsIgnoreCase("min")) {
- getInputHandler().println(Math.min(Double.parseDouble(param1), Double.parseDouble(param2)));
- } else if (operation.equalsIgnoreCase("pow")) {
- getInputHandler().println(Math.pow(Double.parseDouble(param1), Double.parseDouble(param2)));
- } else if (operation.equalsIgnoreCase("round")) {
- getInputHandler().println(Math.round(Double.parseDouble(param1)));
- } else if (operation.equalsIgnoreCase("sqrt")) {
- getInputHandler().println(Math.sqrt(Double.parseDouble(param1)));
- } else if (operation.equalsIgnoreCase("tobinary")) {
- getInputHandler().println(Integer.toBinaryString((int) (Double.parseDouble(param1))));
- } else if (operation.equalsIgnoreCase("size")) {
- getInputHandler().println("Size: " + (lastParen - firstParen - 1));
- } else {
- ret = false;
- }
- } else {
- ret = false;
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- ret = false;
- }
-
- return ret;
- }
-}
diff --git a/src/main/java/cyder/handlers/input/package-info.java b/src/main/java/cyder/handlers/input/package-info.java
deleted file mode 100644
index 2029d315b..000000000
--- a/src/main/java/cyder/handlers/input/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Handlers for the {@link cyder.handlers.input.BaseInputHandler} to pass input from the console's input field to.
- */
-package cyder.handlers.input;
diff --git a/src/main/java/cyder/handlers/internal/ExceptionHandler.java b/src/main/java/cyder/handlers/internal/ExceptionHandler.java
deleted file mode 100644
index 89dc95bd2..000000000
--- a/src/main/java/cyder/handlers/internal/ExceptionHandler.java
+++ /dev/null
@@ -1,359 +0,0 @@
-package cyder.handlers.internal;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.ForReadability;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.constants.CyderRegexPatterns;
-import cyder.constants.HtmlTags;
-import cyder.enumerations.ExitCondition;
-import cyder.exceptions.FatalException;
-import cyder.exceptions.IllegalMethodException;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.FrameType;
-import cyder.ui.frame.enumerations.ScreenPosition;
-import cyder.user.UserDataManager;
-import cyder.utils.OsUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * A class to handle and log exceptions thrown throughout Cyder.
- */
-public final class ExceptionHandler {
- /**
- * The red color used for exception panes.
- */
- private static final Color exceptionRed = new Color(254, 157, 158);
-
- /**
- * The opacity delta to increment/decrement by.
- */
- private static final float opacityShiftDelta = 0.05f;
-
- /**
- * The number of lines to display on an exception preview.
- */
- private static final int shownExceptionLines = 10;
-
- /**
- * The insets offset for the exception label on the frame.
- */
- private static final int offset = 10;
-
- /**
- * The timeout between opacity increments/decrements.
- */
- private static final int opacityTimeout = 20;
-
- /**
- * The prefix for the thread name for exception popup animators.
- */
- private static final String exceptionPopupThreadAnimatorNamePrefix = "Exception Popup Opacity Animator: ";
-
- /**
- * The at keyword to split a stack trace at to find the first line number.
- */
- private static final String AT = "at";
-
- /**
- * The minimum opacity for exception popup animations.
- */
- private static final float minimumOpacity = 0.0f;
-
- /**
- * The maximum opacity for exception popup animations.
- */
- private static final float maximumOpacity = 1.0f;
-
- /**
- * The time the exception popup should be visible between fade-in and fade-out animations.
- */
- private static final int exceptionPopupVisibilityTime = 3000;
-
- /**
- * The exception string.
- */
- private static final String EXCEPTION = "Exception";
-
- /**
- * The name of the thread to animate out exception popups.
- */
- private static final String exceptionPopupDisposeAnimatorThreadName = "Exception popup dispose animator";
-
- /**
- * The font to use for exception popups.
- */
- private static final Font exceptionPopupFont = CyderFonts.DEFAULT_FONT_SMALL;
-
- /**
- * Suppress default constructor.
- */
- private ExceptionHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * Handles an exception by converting it to a string representation and passing it to the {@link Logger}.
- *
- * @param exception the exception to handle
- */
- public static void handle(Exception exception) {
- try {
- Optional optionalWrite = getPrintableException(exception);
- if (optionalWrite.isPresent()) {
- String write = optionalWrite.get();
- if (!write.replaceAll(CyderRegexPatterns.whiteSpaceRegex, "").isEmpty()) {
- Logger.log(LogTag.EXCEPTION, write);
-
- // todo this throws a lot
- boolean consoleOpen = Console.INSTANCE.getUuid() != null && !Console.INSTANCE.isClosed();
- boolean silenceErrors = UserDataManager.INSTANCE.shouldSilenceErrors();
- if (consoleOpen && !silenceErrors) {
- String message = "Exception";
- if (exception != null) {
- String exceptionMessage = exception.getMessage();
- if (exceptionMessage != null && !exceptionMessage.isEmpty()) {
- message = exceptionMessage;
- }
- }
- showExceptionPane(write, message);
- }
- }
- }
- } catch (Exception uhOh) {
- if (exception != null) exception.printStackTrace();
- uhOh.printStackTrace();
- }
- }
-
- /**
- * Shows a popup pane containing a preview of the exception.
- * If the user clicks on the popup, it vanishes immediately and the
- * current log is opened externally.
- *
- * @param printableException the printable exception text
- * @param exceptionMessage the result of invoking {@link Exception#getMessage()}
- */
- private static void showExceptionPane(String printableException, String exceptionMessage) {
- Preconditions.checkNotNull(printableException);
- Preconditions.checkArgument(!printableException.isEmpty());
- Preconditions.checkNotNull(exceptionMessage);
- Preconditions.checkArgument(!exceptionMessage.isEmpty());
-
- AtomicBoolean escapeOpacityThread = new AtomicBoolean();
- ImmutableList exceptionLines = ImmutableList.copyOf(printableException.split(CyderStrings.newline));
-
- int labelWidth = 0;
- for (int i = 0 ; i < shownExceptionLines ; i++) {
- int currentLineWidth = StringUtil.getMinWidth(exceptionLines.get(i), exceptionPopupFont);
- labelWidth = Math.max(labelWidth, currentLineWidth);
- }
-
- int lineHeight = StringUtil.getAbsoluteMinHeight(exceptionLines.get(0), exceptionPopupFont);
- int labelHeight = lineHeight * shownExceptionLines + 2 * offset;
-
- StringBuilder builder = new StringBuilder(HtmlTags.openingHtml);
- for (int i = 0 ; i < shownExceptionLines ; i++) {
- builder.append(exceptionLines.get(i));
- if (i != exceptionLines.size() - 1) builder.append(HtmlTags.breakTag);
- }
- builder.append(HtmlTags.closingHtml);
-
- CyderFrame borderlessFrame = new CyderFrame.Builder()
- .setWidth(labelWidth + 2 * offset)
- .setHeight(labelHeight + 2 * offset)
- .setBackgroundIconFromColor(exceptionRed)
- .setBackgroundColor(exceptionRed)
- .setTitle(exceptionMessage)
- .setType(FrameType.POPUP)
- .setBorderless(true)
- .build();
-
- String labelText = builder.toString();
- JLabel label = generatePopupLabel(labelText, escapeOpacityThread, borderlessFrame);
- label.setBounds(offset, offset, labelWidth, labelHeight);
- borderlessFrame.getContentPane().add(label);
-
- borderlessFrame.setLocationOnScreen(ScreenPosition.BOTTOM_RIGHT);
- borderlessFrame.setOpacity(minimumOpacity);
- borderlessFrame.setVisible(true);
-
- String threadName = exceptionPopupThreadAnimatorNamePrefix + exceptionMessage;
- CyderThreadRunner.submit(() -> {
- try {
- for (float i = minimumOpacity ; i <= maximumOpacity ; i += opacityShiftDelta) {
- if (escapeOpacityThread.get()) return;
- borderlessFrame.setOpacity(i);
- borderlessFrame.repaint();
- ThreadUtil.sleep(opacityTimeout);
- }
-
- borderlessFrame.setOpacity(maximumOpacity);
- borderlessFrame.repaint();
-
- ThreadUtil.sleep(exceptionPopupVisibilityTime);
- if (escapeOpacityThread.get()) return;
-
- for (float i = maximumOpacity ; i >= minimumOpacity ; i -= opacityShiftDelta) {
- if (escapeOpacityThread.get()) return;
- borderlessFrame.setOpacity(i);
- borderlessFrame.repaint();
- ThreadUtil.sleep(opacityTimeout);
- }
-
- borderlessFrame.setOpacity(minimumOpacity);
- borderlessFrame.repaint();
-
- if (escapeOpacityThread.get()) return;
- borderlessFrame.dispose(true);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }, threadName);
- }
-
- /**
- * Generates the label for exception popups.
- *
- * @param labelText the label text
- * @param escapeOpacityThread the atomic boolean for escaping the opacity animation.
- * @param frame the frame the returned JLabel will be added to
- * @return the generated label
- */
- @ForReadability
- private static JLabel generatePopupLabel(String labelText, AtomicBoolean escapeOpacityThread, CyderFrame frame) {
- JLabel label = new JLabel(labelText);
- label.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- escapeOpacityThread.set(true);
-
- CyderThreadRunner.submit(() -> {
- for (float i = frame.getOpacity() ; i >= minimumOpacity ; i -= opacityShiftDelta) {
- frame.setOpacity(i);
- frame.repaint();
- ThreadUtil.sleep(opacityTimeout / 2);
- }
-
- frame.dispose(true);
- }, exceptionPopupDisposeAnimatorThreadName);
- }
- });
- label.setForeground(CyderColors.navy);
- label.setFont(CyderFonts.DEFAULT_FONT_SMALL);
- label.setHorizontalAlignment(JLabel.CENTER);
- label.setVerticalAlignment(JLabel.CENTER);
- return label;
- }
-
- /**
- * Generates a printable version of the exception.
- *
- * @param e the exception to return a printable version of
- * @return Optional String possibly containing exception details and trace
- */
- public static Optional getPrintableException(Exception e) {
- if (e == null) {
- return Optional.empty();
- }
-
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- e.printStackTrace(pw);
- String stackTrace = sw.toString();
-
- ImmutableList stackTraceElements = ImmutableList.copyOf(e.getStackTrace());
- if (stackTraceElements.isEmpty()) return Optional.empty();
- StackTraceElement stackTraceElement = stackTraceElements.get(0);
-
- int lineNumber = stackTraceElement.getLineNumber();
- String lineNumberRepresentation = lineNumber == 0
- ? "Throwing line not found in stacktrace"
- : "From line: " + lineNumber;
-
- String declaringClass = stackTraceElement.getClassName();
- String declaringClassRepresentation = "Declaring class: " + declaringClass;
-
- String filename = stackTraceElement.getFileName();
- String filenameRepresentation = "Filename: " + filename;
-
- String atRegex = CyderRegexPatterns.whiteSpaceRegex + AT + CyderRegexPatterns.whiteSpaceRegex;
- ImmutableList splitStackAt = ImmutableList.copyOf(stackTrace.split(atRegex));
-
- StringBuilder retBuilder = new StringBuilder(CyderStrings.newline);
- if (!splitStackAt.isEmpty()) {
- String origin = splitStackAt.get(0);
- retBuilder.append("Exception origin: ").append(origin);
- } else {
- retBuilder.append("Exception origin not found");
- }
-
- retBuilder.append(CyderStrings.newline).append(filenameRepresentation);
- retBuilder.append(CyderStrings.newline).append(declaringClassRepresentation);
- retBuilder.append(CyderStrings.newline).append(lineNumberRepresentation);
- retBuilder.append(CyderStrings.newline).append("Trace: ").append(stackTrace);
- return Optional.of(retBuilder.toString());
- }
-
- /**
- * Shows a popup with the provided error message. When the opened popup frame is disposed,
- * Cyder exits.
- *
- * @param message the message of the popup
- * @param condition the exit condition to log when exiting
- * @param title the title of the popup
- */
- public static void exceptionExit(String message, ExitCondition condition, String title) {
- Preconditions.checkNotNull(message);
- Preconditions.checkArgument(!message.isEmpty());
- Preconditions.checkNotNull(condition);
- Preconditions.checkNotNull(title);
- Preconditions.checkArgument(!title.isEmpty());
-
- new InformHandler.Builder(message)
- .setTitle(title)
- .setPostCloseAction(() -> OsUtil.exit(condition)).inform();
- }
-
- /**
- * Shows a popup with the provided error message. When the opened popup frame is disposed,
- * Cyder exits.
- *
- * @param message the message of the popup
- * @param condition the exit condition to log when exiting
- */
- public static void exceptionExit(String message, ExitCondition condition) {
- exceptionExit(message, condition, EXCEPTION);
- }
-
- /**
- * Validates the provided condition, throwing a fatal exception if false.
- *
- * @param condition the condition to validate
- * @param fatalExceptionText the exception text if the condition is false
- */
- public static void checkFatalCondition(boolean condition, String fatalExceptionText) {
- Preconditions.checkNotNull(fatalExceptionText);
- Preconditions.checkArgument(!fatalExceptionText.isEmpty());
-
- if (!condition) {
- throw new FatalException(fatalExceptionText);
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/cyder/handlers/internal/InformHandler.java b/src/main/java/cyder/handlers/internal/InformHandler.java
deleted file mode 100644
index ba7981f12..000000000
--- a/src/main/java/cyder/handlers/internal/InformHandler.java
+++ /dev/null
@@ -1,360 +0,0 @@
-package cyder.handlers.internal;
-
-import com.google.common.base.Preconditions;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import cyder.bounds.BoundsString;
-import cyder.bounds.BoundsUtil;
-import cyder.constants.CyderColors;
-import cyder.exceptions.IllegalMethodException;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.ui.drag.CyderDragLabel;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.FrameType;
-import cyder.ui.label.CyderLabel;
-import cyder.utils.HtmlUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-
-/**
- * Information frames throughout Cyder.
- */
-public final class InformHandler {
- /**
- * The width padding on each side of the information pane.
- */
- private static final int frameXPadding = 10;
-
- /**
- * The offset to translate the text label on the information pane down by.
- */
- private static final int frameYOffset = CyderDragLabel.DEFAULT_HEIGHT;
-
- /**
- * THe height padding on each side of the information pane.
- */
- private static final int frameYPadding = 10;
-
- /**
- * Suppress default constructor.
- */
- private InformHandler() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * A quick information pane.
- *
- * @param text the possibly html styled text to display
- * @return a reference to the shown inform frame
- * @throws IllegalArgumentException if the provided text is null
- */
- @CanIgnoreReturnValue /* Calls don't always need the reference */
- public static CyderFrame inform(String text) {
- Preconditions.checkNotNull(text);
-
- return inform(new Builder(text).setTitle(Builder.DEFAULT_TITLE));
- }
-
- /**
- * Opens an information using the information provided by builder.
- *
- * @param builder the builder to use for the construction of the information pane
- * @return a reference to the shown inform frame
- * @throws IllegalArgumentException if the provided builder is null
- */
- @CanIgnoreReturnValue /* Calls don't usually need the reference */
- public static CyderFrame inform(Builder builder) {
- Preconditions.checkNotNull(builder);
-
- CyderFrame informFrame;
-
- // custom container
- if (builder.getContainer() != null) {
- int containerWidth = builder.getContainer().getWidth();
- int containerHeight = builder.getContainer().getHeight();
-
- int xPadding = 1;
- int yTopPadding = CyderDragLabel.DEFAULT_HEIGHT - 4;
- int yBottomPadding = 2;
-
- informFrame = new CyderFrame.Builder()
- .setWidth(containerWidth + 2 * xPadding)
- .setHeight(containerHeight + yTopPadding + yBottomPadding)
- .setTitle(builder.getTitle())
- .build();
-
- JLabel container = builder.getContainer();
- container.setBounds(xPadding, yTopPadding,
- containerWidth, containerHeight);
- informFrame.getContentPane().add(container);
- }
- // intended to generate a text inform pane
- else {
- CyderLabel textLabel = new CyderLabel(builder.getHtmlText());
- textLabel.setOpaque(false);
- textLabel.setForeground(CyderColors.defaultLightModeTextColor);
-
- BoundsString boundsString = BoundsUtil.widthHeightCalculation(builder.getHtmlText());
-
- int containerWidth = boundsString.getWidth();
- int containerHeight = boundsString.getHeight();
-
- textLabel.setText(HtmlUtil.addCenteringToHtml(boundsString.getText()));
-
- builder.setContainer(textLabel);
-
- informFrame = new CyderFrame.Builder()
- .setWidth(containerWidth + frameXPadding * 2)
- .setHeight(containerHeight + frameYOffset + 2 * frameYPadding)
- .build();
- informFrame.setTitle(builder.getTitle());
-
- int containerX = informFrame.getWidth() / 2 - containerWidth / 2;
- int containerY = informFrame.getHeight() / 2 - containerHeight / 2 + 5;
-
- JLabel container = builder.getContainer();
- container.setBounds(containerX, containerY, containerWidth, containerHeight);
- informFrame.add(container);
- }
-
- if (builder.getPreCloseAction() != null) {
- informFrame.addPreCloseAction(builder.getPreCloseAction());
- }
- if (builder.getPostCloseAction() != null) {
- informFrame.addPostCloseAction(builder.getPostCloseAction());
- }
-
- Component relativeTo = builder.getRelativeTo();
-
- // if intended to disable relative to
- if (relativeTo != null && builder.isDisableRelativeTo()) {
- relativeTo.setEnabled(false);
- informFrame.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- relativeTo.setEnabled(true);
- }
- });
- }
-
- informFrame.setFrameType(FrameType.POPUP);
- informFrame.setVisible(true);
- informFrame.setLocationRelativeTo(relativeTo);
-
- Logger.log(LogTag.UI_ACTION, "[INFORMATION PANE] text = \""
- + builder.getHtmlText() + "\", relativeTo = " + builder.getRelativeTo());
-
- return informFrame;
- }
-
- /**
- * A builder for an information pane.
- */
- public static class Builder {
- /**
- * The minimum allowable text length for an information pane.
- */
- public static final int MINIMUM_TEXT_LENGTH = 4;
-
- /**
- * The default title for an information pane which are provided no title.
- */
- public static final String DEFAULT_TITLE = "Information";
-
- /**
- * The text, possibly styled with html elements, to display on the information pane.
- */
- private final String htmlText;
-
- /**
- * The title of this information pane.
- */
- private String title = DEFAULT_TITLE;
-
- /**
- * The component to set this inform frame relative to before the call to setVisible().
- */
- private Component relativeTo;
-
- /**
- * The action to invoke before the frame is closed.
- */
- private Runnable preCloseAction;
-
- /**
- * The action to invoke after the frame is closed.
- */
- private Runnable postCloseAction;
-
- /**
- * The custom container component to layer on the CyderFrame content pane.
- */
- private JLabel container;
-
- /**
- * Whether to disable the relative to component.
- */
- private boolean disableRelativeTo;
-
- /**
- * Default constructor for an inform pane with the required parameters.
- *
- * @param htmlText the html styled text to display on the inform pane
- */
- public Builder(String htmlText) {
- Preconditions.checkNotNull(htmlText);
- Preconditions.checkArgument(StringUtil.getTextLengthIgnoringHtmlTags(htmlText) >= MINIMUM_TEXT_LENGTH);
-
- this.htmlText = htmlText;
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * Returns the text associated with this builder, possibly containing html style tags.
- *
- * @return the text associated with this builder, possibly containing html style tags
- */
- public String getHtmlText() {
- return htmlText;
- }
-
- /**
- * Returns the title for the frame.
- *
- * @return the title for the frame
- */
- public String getTitle() {
- return title;
- }
-
- /**
- * Sets the title for the frame.
- *
- * @param title the title for the frame
- * @return this builder
- */
- @CanIgnoreReturnValue
- public Builder setTitle(String title) {
- this.title = title;
- return this;
- }
-
- /**
- * Returns the component to set the frame relative to.
- *
- * @return the component to set the frame relative to
- */
- public Component getRelativeTo() {
- return relativeTo;
- }
-
- /**
- * Sets the component to set the frame relative to.
- *
- * @param relativeTo the component to set the frame relative to
- * @return this builder
- */
- @CanIgnoreReturnValue
- public Builder setRelativeTo(Component relativeTo) {
- this.relativeTo = relativeTo;
- return this;
- }
-
- /**
- * Returns the pre close action to invoke before disposing the frame.
- *
- * @return the pre close action to invoke before disposing the frame
- */
- public Runnable getPreCloseAction() {
- return preCloseAction;
- }
-
- /**
- * Sets the pre close action to invoke before disposing the frame.
- *
- * @param preCloseAction the pre close action to invoke before disposing the frame
- * @return this builder
- */
- @CanIgnoreReturnValue
- public Builder setPreCloseAction(Runnable preCloseAction) {
- this.preCloseAction = preCloseAction;
- return this;
- }
-
- /**
- * Returns the post close action to invoke before disposing the frame.
- *
- * @return the post close action to invoke before disposing the frame
- */
- public Runnable getPostCloseAction() {
- return postCloseAction;
- }
-
- /**
- * Sets the post close action to invoke before closing the frame.
- *
- * @param postCloseAction the post close action to invoke before closing the frame
- * @return this builder
- */
- @CanIgnoreReturnValue
- public Builder setPostCloseAction(Runnable postCloseAction) {
- this.postCloseAction = postCloseAction;
- return this;
- }
-
- /**
- * Returns the container to use for the frame's pane.
- *
- * @return the container to use for the frame's pane
- */
- public JLabel getContainer() {
- return container;
- }
-
- /**
- * Sets the container to use for the frame's pane.
- *
- * @param container the container to use for the frame's pane
- * @return this builder
- */
- @CanIgnoreReturnValue
- public Builder setContainer(JLabel container) {
- this.container = container;
- return this;
- }
-
- /**
- * Returns whether to disable the relative to component upon showing this dialog.
- *
- * @return whether to disable the relative to component upon showing this dialog
- */
- public boolean isDisableRelativeTo() {
- return disableRelativeTo;
- }
-
- /**
- * Sets whether to disable the relative to component upon showing this dialog.
- *
- * @param disableRelativeTo to disable the relative to component upon showing this dialog
- * @return this builder
- */
- @CanIgnoreReturnValue
- public Builder setDisableRelativeTo(boolean disableRelativeTo) {
- this.disableRelativeTo = disableRelativeTo;
- return this;
- }
-
- /**
- * Creates an information pane using the parameters set by this builder
- */
- public void inform() {
- InformHandler.inform(this);
- }
- }
-}
diff --git a/src/main/java/cyder/login/LoginHandler.java b/src/main/java/cyder/login/LoginHandler.java
deleted file mode 100644
index ef0a95b2c..000000000
--- a/src/main/java/cyder/login/LoginHandler.java
+++ /dev/null
@@ -1,674 +0,0 @@
-package cyder.login;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Widget;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.enumerations.ExitCondition;
-import cyder.exceptions.FatalException;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.managers.CyderVersionManager;
-import cyder.managers.ProgramModeManager;
-import cyder.meta.CyderSplash;
-import cyder.props.Props;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.ui.field.CyderCaret;
-import cyder.ui.field.CyderPasswordField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.pane.CyderOutputPane;
-import cyder.ui.pane.CyderScrollPane;
-import cyder.user.User;
-import cyder.user.UserUtil;
-import cyder.user.creation.UserCreator;
-import cyder.utils.ArrayUtil;
-import cyder.utils.OsUtil;
-import cyder.utils.SecurityUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static cyder.strings.CyderStrings.*;
-
-/**
- * A widget to log into Cyder or any other way that the Console might be invoked.
- */
-public final class LoginHandler {
- /**
- * The width of the login frame.
- */
- public static final int LOGIN_FRAME_WIDTH = 600;
-
- /**
- * The height of the login frame.
- */
- public static final int LOGIN_FRAME_HEIGHT = 400;
-
- /**
- * The frame used for logging into Cyder
- */
- private static CyderFrame loginFrame;
-
- /**
- * The input field for the login frame.
- */
- private static JPasswordField loginField;
-
- /**
- * The text area for the login outputs.
- */
- private static JTextPane loginArea;
-
- /**
- * Whether to perform the login frame typing animation.
- */
- private static boolean doLoginAnimations;
-
- /**
- * The username of the user trying to log in.
- */
- private static String username;
-
- /**
- * The string at the beginning of the input field.
- */
- private static final String defaultBashString = OsUtil.getOsUsername() + "@" + OsUtil.getComputerName() + ":~$ ";
-
- /**
- * The BashString currently being used.
- */
- private static String currentBashString = defaultBashString;
-
- /**
- * Whether the login frame is closed.
- */
- private static boolean loginFrameClosed = true;
-
- /**
- * The background color of the login frame.
- */
- public static final Color backgroundColor = new Color(21, 23, 24);
-
- /**
- * The color used for the output area text.
- */
- public static final Color textColor = new Color(85, 181, 219);
-
- /**
- * The atomic boolean to control whether shift shows the password of the password field.
- */
- private static AtomicBoolean shiftShowsPassword;
-
- /**
- * The regular non-priority printing list for the login frame.
- */
- private static final ArrayList printingList = new ArrayList<>();
-
- /**
- * The priority printing list for the login frame.
- */
- private static final ArrayList priorityPrintingList = new ArrayList<>();
-
- /**
- * The font for the login field.
- */
- private static final Font loginFieldFont = new Font("Agency FB", Font.BOLD, 26);
-
- /**
- * The current login mode
- */
- private static LoginMode loginMode = LoginMode.INPUT;
-
- /**
- * The echo char to use when a password field's text should be visible and not obfuscated.
- */
- private static final char DEFAULT_FIELD_ECHO_CHAR = (char) 0;
-
- /**
- * The timeout in ms between char prints.
- */
- private static final int charTimeout = 20;
-
- /**
- * The timeout in me between line prints.
- */
- private static final int lineTimeout = 400;
-
- /**
- * The name for the login printing animation thread.
- */
- private static final String LOGIN_PRINTING_ANIMATION_THREAD_NAME = "Login Printing Animation";
-
- /**
- * The create command trigger.
- */
- private static final String CREATE = "create";
-
- /**
- * The login command trigger.
- */
- private static final String LOGIN = "login";
-
- /**
- * The quit command trigger.
- */
- private static final String QUIT = "quit";
-
- /**
- * The help command trigger.
- */
- private static final String HELP = "help";
-
- /**
- * The valid commands.
- */
- private static final ImmutableList validCommands = ImmutableList.of(CREATE, LOGIN, QUIT, HELP);
-
- /**
- * The prefix for when the login mode is username.
- */
- private static final String usernameModePrefix = "Username" + colon + space;
-
- /**
- * The prefix for the login frame title.
- */
- private static final String titlePrefix = "Cyder Login" + space;
-
- /**
- * The uuid for the user attempting to log in.
- */
- private static String recognizedUuid = "";
-
- /**
- * Whether Cyder was initially started with a successful AutoCypher
- */
- private static boolean startedViaAutoCypher = false;
-
- /**
- * The list of standard prints to print to the login output pane.
- */
- private static final ImmutableList standardPrints = ImmutableList.of(
- "Cyder version: " + CyderVersionManager.INSTANCE.getVersion() + newline,
- "Type " + quote + HELP + quote + " for a list of valid commands" + newline,
- "Build: " + CyderVersionManager.INSTANCE.getReleaseDate() + newline,
- "Author: Nate Cheshire" + newline,
- "Description: A programmer's swiss army knife" + newline
- );
-
- /**
- * Suppress default constructor.
- */
- private LoginHandler() {
- throw new IllegalMethodException(ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * Begins the login typing animation and printing thread.
- */
- private static void startTypingAnimation() {
- doLoginAnimations = true;
- printingList.clear();
-
- printingList.addAll(standardPrints);
-
- CyderOutputPane outputPane = new CyderOutputPane(loginArea);
-
- CyderThreadRunner.submit(() -> {
- try {
- while (doLoginAnimations && loginFrame != null) {
- if (!priorityPrintingList.isEmpty()) {
- if (!outputPane.acquireLock()) {
- throw new FatalException("Failed to acquire output pane lock");
- }
-
- String line = priorityPrintingList.remove(0);
- Logger.log(LogTag.LOGIN_OUTPUT, line);
-
- ArrayUtil.toList(line.toCharArray()).forEach(charizard -> {
- outputPane.getStringUtil().print(String.valueOf(charizard));
- ThreadUtil.sleep(charTimeout);
- });
-
- outputPane.releaseLock();
- } else if (!printingList.isEmpty()) {
- if (!outputPane.acquireLock()) {
- throw new FatalException("Failed to acquire output pane lock");
- }
-
- String line = printingList.remove(0);
- Logger.log(LogTag.LOGIN_OUTPUT, line);
-
- ArrayUtil.toList(line.toCharArray()).forEach(charizard -> {
- outputPane.getStringUtil().print(String.valueOf(charizard));
- ThreadUtil.sleep(charTimeout);
- });
-
- outputPane.releaseLock();
- }
-
- ThreadUtil.sleep(lineTimeout);
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, LOGIN_PRINTING_ANIMATION_THREAD_NAME);
- }
-
- /**
- * Shows the login frame
- */
- @Widget(triggers = {"login", "pin"}, description = "A widget to switch between Cyder users")
- public static void showGui() {
- showGui(null);
- }
-
- /**
- * Shows the login frame relative to the provided point.
- *
- * @param centerPoint the point to place the center of the login frame at
- */
- public static void showGui(Point centerPoint) {
- priorityPrintingList.clear();
- printingList.clear();
- loginMode = LoginMode.INPUT;
-
- if (loginFrame != null) {
- loginFrame.removePostCloseActions();
- loginFrame.dispose(true);
- }
-
- loginFrame = new CyderFrame.Builder()
- .setWidth(LOGIN_FRAME_WIDTH)
- .setHeight(LOGIN_FRAME_HEIGHT)
- .setBackgroundIconFromColor(backgroundColor)
- .setTitle(titlePrefix + openingBracket + CyderVersionManager.INSTANCE.getVersion()
- + space + "Build" + closingBracket)
- .build();
- loginFrame.setBackground(backgroundColor);
- loginFrame.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- loginFrameClosed = true;
- doLoginAnimations = false;
- if (Console.INSTANCE.isClosed()) {
- OsUtil.exit(ExitCondition.StandardControlledExit);
- }
- }
-
- public void windowOpened(WindowEvent e) {
- loginField.requestFocus();
- }
- });
- loginFrameClosed = false;
-
- loginArea = new JTextPane();
- loginArea.setBounds(20, 40, 560, 280);
- loginArea.setBackground(backgroundColor);
- loginArea.setBorder(null);
- loginArea.setFocusable(false);
- loginArea.setEditable(false);
- loginArea.setFont(loginFieldFont);
- loginArea.setForeground(textColor);
- loginArea.setCaretColor(loginArea.getForeground());
- CyderScrollPane loginScroll = new CyderScrollPane(loginArea,
- ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
- loginScroll.setThumbColor(CyderColors.regularPink);
- loginScroll.setBounds(20, 40, 560, 280);
- loginScroll.getViewport().setOpaque(false);
- loginScroll.setOpaque(false);
- loginScroll.setBorder(null);
- loginArea.setAutoscrolls(true);
- loginFrame.getContentPane().add(loginScroll);
-
- loginField = new JPasswordField(20);
- loginField.setEchoChar(DEFAULT_FIELD_ECHO_CHAR);
- loginField.setText(currentBashString);
- loginField.setBounds(20, 340, 560, 40);
- loginField.setBackground(backgroundColor);
- loginField.setBorder(null);
- loginField.setCaret(new CyderCaret(loginArea.getForeground()));
- loginField.setSelectionColor(CyderColors.selectionColor);
- loginField.setFont(loginFieldFont);
- loginField.setForeground(textColor);
- loginField.setCaretColor(textColor);
- loginField.addActionListener(e -> loginField.requestFocusInWindow());
- loginField.addKeyListener(new KeyAdapter() {
- @Override
- public void keyTyped(KeyEvent event) {
- loginFieldEnterAction(event);
- }
-
- @Override
- public void keyPressed(KeyEvent event) {
- correctLoginFieldCaretPosition();
- }
-
- @Override
- public void keyReleased(KeyEvent event) {
- correctLoginFieldCaretPosition();
- }
- });
-
- shiftShowsPassword = CyderPasswordField.addShiftShowsPasswordListener(loginField);
- shiftShowsPassword.set(false);
-
- loginField.setCaretPosition(currentBashString.length());
- loginFrame.getContentPane().add(loginField);
- if (centerPoint == null) {
- loginFrame.finalizeAndShow();
- } else {
- loginFrame.finalizeAndShow(centerPoint);
- }
-
- CyderSplash.INSTANCE.fastDispose();
- if (UserUtil.noCyderUsers()) printlnPriority("No users found; please type " + quote + CREATE + quote);
- startTypingAnimation();
- }
-
- /**
- * Checks for the caret position in the login field being before the current bash string
- */
- private static void correctLoginFieldCaretPosition() {
- if (loginMode != LoginMode.PASSWORD) {
- int caretPosition = loginField.getCaretPosition();
- int length = loginField.getPassword().length;
- String prefix = switch (loginMode) {
- case INPUT -> defaultBashString;
- case USERNAME -> usernameModePrefix;
- default -> throw new IllegalStateException("Invalid login mode: " + loginMode);
- };
- boolean beforeBashString = caretPosition < prefix.length();
- if (beforeBashString) loginField.setCaretPosition(length);
- }
- }
-
- /**
- * Checks for whether the backspace is being pressed and whether that will
- * result in part of the bash string being deleted.
- *
- * @param keyChar the key char being typed
- * @return whether the backspace is being pressed and whether that will
- * result in part of the bash string being deleted
- */
- @ForReadability
- private static boolean checkForBackspaceIntoBashString(char keyChar) {
- boolean backSpaceAndBashString = keyChar == KeyEvent.VK_BACK_SPACE && loginMode != LoginMode.PASSWORD;
- if (backSpaceAndBashString) {
- if (loginField.getPassword().length < currentBashString.length()) {
- loginField.setText(currentBashString);
- }
-
- return true;
- }
-
- return false;
- }
-
- /**
- * The actions to invoke when a key is pressed in the login field.
- *
- * @param event the key event
- */
- private static void loginFieldEnterAction(KeyEvent event) {
- char keyChar = event.getKeyChar();
- if (checkForBackspaceIntoBashString(keyChar)) {
- event.consume();
- return;
- }
-
- if (keyChar != newline.charAt(0)) {
- return;
- }
-
- String userInput = "";
- char[] fieldInput = loginField.getPassword();
- if (loginMode != LoginMode.PASSWORD) {
- userInput = new String(fieldInput).substring(currentBashString.length());
- Logger.log(LogTag.LOGIN_INPUT, userInput);
- }
-
- switch (loginMode) {
- case INPUT -> onInputEntered(userInput);
- case USERNAME -> onUsernameEntered(userInput);
- case PASSWORD -> onPasswordEntered(fieldInput);
- }
-
- Arrays.fill(fieldInput, '\0');
- }
-
- /**
- * Handles the user entering input when the login mode is {@link LoginMode#INPUT}.
- *
- * @param userInput the current field input with the bash string parsed away
- */
- private static void onInputEntered(String userInput) {
- if (userInput.equalsIgnoreCase(CREATE)) {
- UserCreator.showGui();
- loginField.setText(currentBashString);
- } else if (userInput.equalsIgnoreCase(LOGIN)) {
- currentBashString = usernameModePrefix;
- loginField.setText(currentBashString);
- printlnPriority("Awaiting Username");
- loginMode = LoginMode.USERNAME;
- } else if (userInput.equalsIgnoreCase(QUIT)) {
- loginFrame.dispose();
- } else if (userInput.equalsIgnoreCase(HELP)) {
- loginField.setText(currentBashString);
- printlnPriority("Valid commands: ");
- validCommands.forEach(command -> LoginHandler.printlnPriority(
- BULLET_POINT + space + command));
- } else {
- loginField.setText(currentBashString);
- printlnPriority("Unknown command; See " + quote + HELP + quote + " for " + HELP);
- }
- }
-
- /**
- * Handles the user entering input when the login mode is {@link LoginMode#USERNAME}.
- *
- * @param userInput the current field input with the bash string parsed away
- */
- private static void onUsernameEntered(String userInput) {
- username = userInput;
- loginMode = LoginMode.PASSWORD;
- loginField.setEchoChar(ECHO_CHAR);
- loginField.setText("");
- printlnPriority("Awaiting Password (hold shift to reveal password)");
- currentBashString = defaultBashString;
- shiftShowsPassword.set(true);
- }
-
- /**
- * Handles the user entering input when the login mode is {@link LoginMode#PASSWORD}.
- *
- * @param fieldInput the current field input
- */
- private static void onPasswordEntered(char[] fieldInput) {
- loginField.setEchoChar(DEFAULT_FIELD_ECHO_CHAR);
- shiftShowsPassword.set(false);
- loginField.setText("");
- printlnPriority("Attempting validation");
-
- String hashedPassword = SecurityUtil.toHexString(SecurityUtil.getSha256(fieldInput));
- if (recognize(username, hashedPassword, false)) {
- loginFrame.dispose(true);
- return;
- }
-
- loginField.setEchoChar(DEFAULT_FIELD_ECHO_CHAR);
- loginField.setText(currentBashString);
- loginField.setCaretPosition(currentBashString.length());
-
- printlnPriority("Login failed");
- loginMode = LoginMode.INPUT;
- username = "";
- }
-
- /**
- * Adds the provided line follows by a new line character to the priority printing list
- *
- * @param line the line to add
- */
- private static void printlnPriority(String line) {
- priorityPrintingList.add(line + newline);
- }
-
- /**
- * Whether the login frame is closed.
- *
- * @return the login frame is closed
- */
- public static boolean isLoginFrameClosed() {
- return loginFrameClosed;
- }
-
- /**
- * Returns the login frame.
- *
- * @return the login frame
- */
- public static CyderFrame getLoginFrame() {
- return loginFrame;
- }
-
- /**
- * Returns whether Cyder was initially started with a successful AutoCypher.
- *
- * @return whether Cyder was initially started with a successful AutoCypher
- */
- public static boolean wasStartedViaAutoCypher() {
- return startedViaAutoCypher;
- }
-
- /**
- * Begins the login sequence to figure out how to enter Cyder and which frame to show, that of
- * the console, the login frame, or an exception pane.
- */
- public static void showProperStartupFrame() {
- boolean autoCypher = Props.autocypher.getValue();
-
- if (autoCypher) {
- boolean debugHashNamePresent = Props.autocypherName.valuePresent();
- boolean debugHashPasswordPresent = Props.autocypherPassword.valuePresent();
-
- if (debugHashNamePresent && debugHashPasswordPresent) {
- String name = Props.autocypherName.getValue();
- String password = Props.autocypherPassword.getValue();
-
- startedViaAutoCypher = recognize(name, password, true);
- ProgramModeManager.INSTANCE.refreshProgramMode();
- if (startedViaAutoCypher) return;
- }
-
- showGui();
- return;
- }
-
- boolean released = CyderVersionManager.INSTANCE.isReleased();
- if (!released) {
- ExceptionHandler.exceptionExit("Unreleased build of Cyder", ExitCondition.NotReleased);
- return;
- }
-
- Optional optionalUuid = UserUtil.getMostRecentLoggedInUser();
- if (optionalUuid.isPresent()) {
- String loggedInUuid = optionalUuid.get();
- Logger.log(LogTag.CONSOLE_LOAD, "Found previously logged in user: " + loggedInUuid);
- UserUtil.logoutAllUsers();
- Console.INSTANCE.initializeAndLaunch(loggedInUuid);
- return;
- }
-
- showGui();
- }
-
- /**
- * Rests the state variables prior to the logic of {@link #recognize(String, String, boolean)}.
- */
- private static void resetRecognitionVars() {
- recognizedUuid = "";
- }
-
- /**
- * Attempts to log in a user based on the provided
- * name and an already hashed password.
- *
- * @param name the provided user account name
- * @param hashedPass the password already having been hashed
- * @return whether the name and pass combo was authenticated and logged in
- */
- public static boolean recognize(String name, String hashedPass, boolean autoCypherAttempt) {
- resetRecognitionVars();
-
- switch (validateUsernamePassword(name, hashedPass)) {
- case FAILED -> {
- printlnPriority(autoCypherAttempt ? "AutoCypher failed" : "Incorrect password");
- if (!autoCypherAttempt) loginField.requestFocusInWindow();
- return false;
- }
- case UNKNOWN_USER -> {
- printlnPriority("Unknown user");
- return false;
- }
- case SUCCESS -> {
- Preconditions.checkState(!recognizedUuid.isEmpty());
-
- Console.INSTANCE.setConsoleLoadStartTime();
-
- if (!Console.INSTANCE.isClosed()) {
- Console.INSTANCE.releaseResourcesAndCloseFrame(false);
- Console.INSTANCE.logoutCurrentUser();
- }
-
- doLoginAnimations = false;
-
- Console.INSTANCE.initializeAndLaunch(recognizedUuid);
-
- return true;
- }
- default -> throw new IllegalArgumentException("Invalid password status");
- }
- }
-
- /**
- * Checks whether the given name/pass combo is valid and returns the result of the check.
- *
- * @param providedUsername the username given
- * @param singlyHashedPassword the singly-hashed password
- * @return the result of checking for a user with the provided name and password
- */
- private static PasswordCheckResult validateUsernamePassword(String providedUsername, String singlyHashedPassword) {
- ArrayList names = new ArrayList<>();
- UserUtil.getUserJsons().forEach(userJson -> names.add(UserUtil.extractUser(userJson).getUsername()));
-
- if (names.stream().map(String::toLowerCase).noneMatch(name -> name.equalsIgnoreCase(providedUsername))) {
- return PasswordCheckResult.UNKNOWN_USER;
- }
-
- for (File userJsonFile : UserUtil.getUserJsons()) {
- User user = UserUtil.extractUser(userJsonFile);
- if (providedUsername.equalsIgnoreCase(user.getUsername())
- && SecurityUtil.hashAndHex(singlyHashedPassword).equals(user.getPassword())) {
- recognizedUuid = userJsonFile.getParentFile().getName();
- return PasswordCheckResult.SUCCESS;
- }
- }
-
- return PasswordCheckResult.FAILED;
- }
-}
diff --git a/src/main/java/cyder/login/LoginMode.java b/src/main/java/cyder/login/LoginMode.java
deleted file mode 100644
index 10f172ad2..000000000
--- a/src/main/java/cyder/login/LoginMode.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cyder.login;
-
-/**
- * The valid login modes.
- */
-enum LoginMode {
- /**
- * Expecting general input.
- */
- INPUT,
-
- /**
- * Expecting a username.
- */
- USERNAME,
-
- /**
- * Expecting a password.
- */
- PASSWORD
-}
diff --git a/src/main/java/cyder/login/PasswordCheckResult.java b/src/main/java/cyder/login/PasswordCheckResult.java
deleted file mode 100644
index 17768b053..000000000
--- a/src/main/java/cyder/login/PasswordCheckResult.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cyder.login;
-
-/**
- * The result of a password check.
- */
-enum PasswordCheckResult {
- /**
- * The login failed due to invalid credentials.
- */
- FAILED,
-
- /**
- * The login failed due to not being able to locate the username.
- */
- UNKNOWN_USER,
-
- /**
- * The login succeeded and the user uuid should be present.
- */
- SUCCESS
-}
diff --git a/src/main/java/cyder/login/package-info.java b/src/main/java/cyder/login/package-info.java
deleted file mode 100644
index cdd303ed8..000000000
--- a/src/main/java/cyder/login/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Utilities and classes related to the logging in process.
- */
-package cyder.login;
diff --git a/src/main/java/cyder/managers/CyderVersionManager.java b/src/main/java/cyder/managers/CyderVersionManager.java
deleted file mode 100644
index a751ec744..000000000
--- a/src/main/java/cyder/managers/CyderVersionManager.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package cyder.managers;
-
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-
-/**
- * A manager for the program's name, version name, release date, released state, and similar states.
- */
-@SuppressWarnings("FieldCanBeLocal") /* Readability */
-public enum CyderVersionManager {
- /**
- * The version manager instance.
- */
- INSTANCE;
-
- /**
- * Constructor explicitly defined for logging purposes.
- */
- CyderVersionManager() {
- Logger.log(LogTag.OBJECT_CREATION, "Version manager constructed");
- }
-
- /**
- * The program name.
- */
- private final String programName = "Cyder";
-
- /**
- * The version name.
- */
- private final String version = "Liminal";
-
- /**
- * The date of release.
- */
- private final String releaseDate = "Not Yet Released";
-
- /**
- * Whether this release is publicly available.
- */
- private final boolean released = false;
-
- /**
- * Returns the program name.
- *
- * @return the program name
- */
- public String getProgramName() {
- return programName;
- }
-
- /**
- * Returns the name for this version.
- *
- * @return the name for this version
- */
- public String getVersion() {
- return version;
- }
-
- /**
- * Returns the release date for this version.
- *
- * @return the release date for this version
- */
- public String getReleaseDate() {
- return releaseDate;
- }
-
- /**
- * Returns whether this release is publicly available.
- *
- * @return whether this release is publicly available
- */
- public boolean isReleased() {
- return released;
- }
-}
diff --git a/src/main/java/cyder/managers/ProgramMode.java b/src/main/java/cyder/managers/ProgramMode.java
deleted file mode 100644
index 2f2ef66d1..000000000
--- a/src/main/java/cyder/managers/ProgramMode.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cyder.managers;
-
-/**
- * Possible modes Cyder can exist in for a certain instance.
- */
-public enum ProgramMode {
- /**
- * The normal, user mode for Cyder, started from a JAR file.
- */
- NORMAL("Normal", 0),
-
- /**
- * Cyder was started from an IDE and not a JAR file.
- */
- IDE_NORMAL("IDE Normal", 1),
-
- /**
- * Cyder was started in a debug mode by an IDE.
- */
- IDE_DEBUG("IDE Debug", 2),
-
- /**
- * Cyder was started via an AutoCypher.
- */
- DEVELOPER_DEBUG("Developer Debug", 3);
-
- /**
- * The name of the program mode.
- */
- private final String name;
-
- /**
- * The level of priority of the program mode.
- */
- private final int priorityLevel;
-
- ProgramMode(String name, int priorityLevel) {
- this.name = name;
- this.priorityLevel = priorityLevel;
- }
-
- /**
- * Returns the name of the program mode.
- *
- * @return the name of the program mode
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the priority level of the program mode.
- *
- * @return the priority level of the program mode
- */
- public int getPriorityLevel() {
- return priorityLevel;
- }
-
- /**
- * Returns whether this priority level has developer priority.
- *
- * @return whether this priority level has developer priority
- */
- public boolean hasDeveloperPriorityLevel() {
- return priorityLevel >= IDE_NORMAL.getPriorityLevel();
- }
-}
diff --git a/src/main/java/cyder/managers/ProgramModeManager.java b/src/main/java/cyder/managers/ProgramModeManager.java
deleted file mode 100644
index 3fba615ff..000000000
--- a/src/main/java/cyder/managers/ProgramModeManager.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package cyder.managers;
-
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.login.LoginHandler;
-import cyder.utils.JvmUtil;
-import cyder.utils.OsUtil;
-
-/**
- * A manager for the program mode.
- */
-public enum ProgramModeManager {
- /**
- * The program mode manager instance.
- */
- INSTANCE;
-
- /**
- * The program mode for this session of Cyder.
- */
- private static ProgramMode sessionProgramMode = ProgramMode.NORMAL;
-
- /**
- * Refreshes the current program mode.
- */
- public void refreshProgramMode() {
- if (LoginHandler.wasStartedViaAutoCypher()) {
- sessionProgramMode = ProgramMode.DEVELOPER_DEBUG;
- } else if (JvmUtil.currentInstanceLaunchedWithDebug()) {
- sessionProgramMode = ProgramMode.IDE_DEBUG;
- } else if (!OsUtil.JAR_MODE) {
- sessionProgramMode = ProgramMode.IDE_NORMAL;
- } else {
- sessionProgramMode = ProgramMode.NORMAL;
- }
-
- Logger.log(LogTag.DEBUG, "Refreshed program mode, set as: " + sessionProgramMode.getName());
- }
-
- /**
- * Returns the program mode for this session of Cyder.
- *
- * @return the program mode for this session of Cyder
- */
- public ProgramMode getProgramMode() {
- return sessionProgramMode;
- }
-}
diff --git a/src/main/java/cyder/ui/frame/tooltip/TooltipMenuController.java b/src/main/java/cyder/ui/frame/tooltip/TooltipMenuController.java
index a516a1bd9..59f09bbe0 100644
--- a/src/main/java/cyder/ui/frame/tooltip/TooltipMenuController.java
+++ b/src/main/java/cyder/ui/frame/tooltip/TooltipMenuController.java
@@ -10,7 +10,6 @@
import cyder.files.FileUtil;
import cyder.getter.GetInputBuilder;
import cyder.getter.GetterUtil;
-import cyder.managers.ProgramModeManager;
import cyder.props.Props;
import cyder.strings.StringUtil;
import cyder.threads.CyderThreadFactory;
diff --git a/src/main/java/cyder/user/UserData.java b/src/main/java/cyder/user/UserData.java
index 16bfec4e9..126c12cc2 100644
--- a/src/main/java/cyder/user/UserData.java
+++ b/src/main/java/cyder/user/UserData.java
@@ -14,7 +14,6 @@
import cyder.ui.list.CyderScrollList;
import cyder.user.data.MappedExecutables;
import cyder.user.data.ScreenStat;
-import cyder.weather.WeatherWidget;
import cyder.widgets.ClockWidget;
import javax.swing.*;
diff --git a/src/main/java/cyder/utils/OsUtil.java b/src/main/java/cyder/utils/OsUtil.java
index 68d3ac54e..fb2f7c347 100644
--- a/src/main/java/cyder/utils/OsUtil.java
+++ b/src/main/java/cyder/utils/OsUtil.java
@@ -10,7 +10,6 @@
import cyder.handlers.internal.ExceptionHandler;
import cyder.logging.LogTag;
import cyder.logging.Logger;
-import cyder.managers.ProgramModeManager;
import cyder.managers.RobotManager;
import cyder.meta.Cyder;
import cyder.strings.CyderStrings;
diff --git a/src/main/java/cyder/utils/StatUtil.java b/src/main/java/cyder/utils/StatUtil.java
index 298d0abae..bfc3106be 100644
--- a/src/main/java/cyder/utils/StatUtil.java
+++ b/src/main/java/cyder/utils/StatUtil.java
@@ -9,8 +9,6 @@
import cyder.exceptions.IllegalMethodException;
import cyder.files.FileUtil;
import cyder.handlers.internal.ExceptionHandler;
-import cyder.managers.ProgramMode;
-import cyder.managers.ProgramModeManager;
import cyder.network.IpDataManager;
import cyder.network.LatencyManager;
import cyder.network.NetworkUtil;
diff --git a/src/main/java/cyder/weather/MeasurementScale.java b/src/main/java/cyder/weather/MeasurementScale.java
new file mode 100644
index 000000000..71e78aea0
--- /dev/null
+++ b/src/main/java/cyder/weather/MeasurementScale.java
@@ -0,0 +1,31 @@
+package cyder.weather;
+
+/**
+ * Possible measurement scales, that of imperial or metric.
+ */
+public enum MeasurementScale {
+ /**
+ * The imperial measurement scale.
+ */
+ IMPERIAL("imperial"),
+
+ /**
+ * The metric measurement scale.
+ */
+ METRIC("metric");
+
+ private final String weatherDataRepresentation;
+
+ MeasurementScale(String weatherDataRepresentation) {
+ this.weatherDataRepresentation = weatherDataRepresentation;
+ }
+
+ /**
+ * Returns the weather data representation for this measurement scale.
+ *
+ * @return the weather data representation for this measurement scale
+ */
+ public String getWeatherDataRepresentation() {
+ return weatherDataRepresentation;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cyder/weather/WeatherUtil.java b/src/main/java/cyder/weather/WeatherUtil.java
index 03ec7a6df..6a3bee669 100644
--- a/src/main/java/cyder/weather/WeatherUtil.java
+++ b/src/main/java/cyder/weather/WeatherUtil.java
@@ -3,13 +3,13 @@
import com.google.common.base.Preconditions;
import cyder.constants.CyderUrls;
import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
import cyder.props.Props;
import cyder.strings.CyderStrings;
import cyder.utils.SerializationUtil;
import cyder.weather.parsers.WeatherData;
import java.io.BufferedReader;
+import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Optional;
@@ -35,36 +35,6 @@ private WeatherUtil() {
throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
}
- /**
- * Possible measurement scales, that of imperial or metric.
- */
- public enum MeasurementScale {
- /**
- * The imperial measurement scale.
- */
- IMPERIAL("imperial"),
-
- /**
- * The metric measurement scale.
- */
- METRIC("metric");
-
- private final String weatherDataRepresentation;
-
- MeasurementScale(String weatherDataRepresentation) {
- this.weatherDataRepresentation = weatherDataRepresentation;
- }
-
- /**
- * Returns the weather data representation for this measurement scale.
- *
- * @return the weather data representation for this measurement scale
- */
- public String getWeatherDataRepresentation() {
- return weatherDataRepresentation;
- }
- }
-
/**
* Returns the weather data object for the provided location string if available. Empty optional else.
*
@@ -84,8 +54,8 @@ public static Optional getWeatherData(String locationString) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(OpenString).openStream()))) {
return Optional.of(SerializationUtil.fromJson(reader, WeatherData.class));
- } catch (Exception e) {
- ExceptionHandler.handle(e);
+ } catch (IOException e) {
+ e.printStackTrace();
}
return Optional.empty();
diff --git a/src/main/java/cyder/weather/WeatherWidget.java b/src/main/java/cyder/weather/WeatherWidget.java
deleted file mode 100644
index e89f97fcd..000000000
--- a/src/main/java/cyder/weather/WeatherWidget.java
+++ /dev/null
@@ -1,1204 +0,0 @@
-package cyder.weather;
-
-import com.google.common.base.Preconditions;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.constants.CyderRegexPatterns;
-import cyder.constants.HtmlTags;
-import cyder.enumerations.Extension;
-import cyder.enumerations.Units;
-import cyder.getter.GetInputBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.math.AngleUtil;
-import cyder.math.InterpolationUtil;
-import cyder.network.IpDataManager;
-import cyder.network.NetworkUtil;
-import cyder.parsers.ip.IpData;
-import cyder.props.Props;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.time.TimeUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.drag.button.DragLabelTextButton;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.notification.NotificationBuilder;
-import cyder.user.UserDataManager;
-import cyder.utils.HtmlUtil;
-import cyder.utils.ImageUtil;
-import cyder.utils.MapUtil;
-import cyder.utils.StaticUtil;
-import cyder.weather.parsers.WeatherData;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.text.DecimalFormat;
-import java.text.SimpleDateFormat;
-import java.time.Duration;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Collectors;
-
-import static cyder.strings.CyderStrings.*;
-
-/**
- * A widget for showing the weather for a local area.
- */
-@Vanilla
-@CyderAuthor
-public class WeatherWidget {
- /**
- * The current location label.
- */
- private JLabel locationLabel;
-
- /**
- * The current weather description label.
- */
- private JLabel currentWeatherLabel;
-
- /**
- * The custom painted temperature label container to hold the min, current, and max temperatures.
- */
- private JLabel customTempLabel;
-
- /**
- * The wind speed label.
- */
- private JLabel windSpeedLabel;
-
- /**
- * The custom painted wind direction label.
- */
- private JLabel windDirectionLabel;
-
- /**
- * The humidity label.
- */
- private JLabel humidityLabel;
-
- /**
- * The pressure label.
- */
- private JLabel pressureLabel;
-
- /**
- * The sunset label.
- */
- private JLabel sunsetLabel;
-
- /**
- * The sunrise label.
- */
- private JLabel sunriseLabel;
-
- /**
- * The timezone label.
- */
- private JLabel timezoneLabel;
-
- /**
- * The current time label.
- */
- private JLabel currentTimeLabel;
-
- /**
- * The current weather icon label.
- */
- private JLabel currentWeatherIconLabel;
-
- /**
- * The current temperature label
- */
- private JLabel currentTempLabel;
-
- /**
- * The min temperature label.
- */
- private JLabel minTempLabel;
-
- /**
- * The max temperature label.
- */
- private JLabel maxTempLabel;
-
- /**
- * The sunrise time in unix time format.
- */
- private long sunriseMillis = 0L;
-
- /**
- * The sunset time in unix time format.
- */
- private long sunsetMillis = 0L;
-
- /**
- * The sunrise time to display on the label.
- */
- private String sunriseFormatted = "";
-
- /**
- * The sunset time to display on the label.
- */
- private String sunsetFormatted = "";
-
- /**
- * The sunrise hour.
- */
- private int sunriseHour;
-
- /**
- * The sunset hour.
- */
- private int sunsetHour;
-
- /**
- * The current weather icon resource.
- */
- private String weatherIconId = "01d";
-
- /**
- * The current weather condition.
- */
- private String weatherCondition = "";
-
- /**
- * The current wind speed.
- */
- private float windSpeed = 0f;
-
- /**
- * The current temperature.
- */
- private float temperature = 0f;
-
- /**
- * The current humidity.
- */
- private float humidity = 0f;
-
- /**
- * The current pressure.
- */
- private float pressure = 0f;
-
- /**
- * The current wind direction.
- */
- private float windBearing = 0f;
-
- /**
- * The current location.
- */
- private String currentLocationString = "";
-
- /**
- * The previous location.
- */
- private String previousLocationString = "";
-
- /**
- * The currently set city.
- */
- private String userCity = "";
-
- /**
- * The currently set state.
- */
- private String userState = "";
-
- /**
- * The currently set country.
- */
- private String userCountry = "";
-
- /**
- * The weather frame.
- */
- private CyderFrame weatherFrame;
-
- /**
- * Whether to use the custom location.
- */
- private boolean useCustomLoc;
-
- /**
- * Whether to repull weather data every updateFrequency minutes.
- */
- private final AtomicBoolean stopUpdating = new AtomicBoolean(false);
-
- /**
- * The maximum temperature
- */
- private float minTemp;
-
- /**
- * The minimum temperature.
- */
- private float maxTemp;
-
- /**
- * The gmt offset for the current location.
- */
- private int parsedGmtOffset;
-
- /**
- * The last gmt offset returned when parsing weather data.
- */
- private String weatherDataGmtOffset = "0";
-
- /**
- * Whether the gmt offset has been set.
- */
- private boolean isGmtSet;
-
- /**
- * The width of the frame.
- */
- private static final int FRAME_WIDTH = 480;
-
- /**
- * The height of the frame.
- */
- private static final int FRAME_HEIGHT = 640;
-
- /**
- * The weather keyword.
- */
- private static final String WEATHER = "weather";
-
- /**
- * The default frame title.
- */
- private static final String DEFAULT_TITLE = WEATHER;
-
- /**
- * The shade color for the default background.
- */
- private static final Color shadeColor = new Color(89, 85, 161);
-
- /**
- * The primary color for the default background.
- */
- private static final Color primaryColorOne = new Color(205, 119, 130);
-
- /**
- * The primary color for the default background.
- */
- private static final Color primaryColorTwo = new Color(38, 21, 75);
-
- /**
- * The default frame background.
- */
- private static final BufferedImage defaultBackground = ImageUtil.getImageGradient(FRAME_WIDTH, FRAME_HEIGHT,
- primaryColorOne, primaryColorTwo, shadeColor);
-
- /**
- * The number of seconds in a singular hour.
- */
- private static final int SECONDS_IN_HOUR = 3600;
-
- /**
- * The post meridiem string
- */
- private static final String PM = "pm";
-
- /**
- * The ante meridiem string.
- */
- private static final String AM = "am";
-
- /**
- * The component width for the custom temperature label.
- */
- private static final int customTempLabelWidth = 400;
-
- /**
- * The name for the waiting thread for changing the widget's location.
- */
- private static final String WEATHER_LOCATION_CHANGER_THREAD_NAME = "Weather Location Changer";
-
- /**
- * The description for the @Widget annotation.
- */
- private static final String widgetDescription = "A widget that displays weather data for the current " +
- "city you are in. The location is also changeable";
-
- /**
- * The getter util instance for changing the weather location.
- */
- private final GetterUtil getterUtilInstance = GetterUtil.getInstance();
-
- /**
- * The instances of weather widget for this Cyder session.
- */
- private static final ArrayList instances = new ArrayList<>();
-
- /**
- * The gmt keyword.
- */
- private static final String GMT = "GMT";
-
- /**
- * The number of comma separated parts for a valid location string.
- */
- private static final int cityStateCountryFormatLen = 3;
-
- /**
- * The index of the state abbreviation in a city state country string.
- */
- private static final int stateIndex = 1;
-
- /**
- * The length of USA state abbreviations.
- */
- private static final int stateAbbrLen = 2;
-
- /**
- * The day time identifier.
- */
- private static final String DAY_IMAGE_ID = "d";
-
- /**
- * The night time identifier.
- */
- private static final String NIGHT_IMAGE_ID = "n";
-
- /**
- * The value to add to the center x value for the temperature label within the custom painted component.
- */
- private static final int temperatureLineCenterAdditive = 5;
-
- /**
- * The refreshed keyword.
- */
- private static final String REFRESHED = "Refreshed";
-
- /**
- * The dst active bracketed text.
- */
- private static final String DST_ACTIVE = "DST Active";
-
- /**
- * The date formatter for the sunrise and sunset times.
- */
- private static final SimpleDateFormat sunriseSunsetFormat = new SimpleDateFormat("h:mm");
-
- /**
- * The builder for acquiring the map view.
- */
- private final MapUtil.Builder mapViewBuilder = new MapUtil.Builder(
- FRAME_WIDTH, FRAME_HEIGHT, Props.mapQuestApiKey.getValue())
- .setFilterWaterMark(true)
- .setScaleBarLocation(MapUtil.ScaleBarLocation.BOTTOM);
-
- /**
- * The north cardinal direction abbreviation.
- */
- private static final String NORTH = "N";
-
- /**
- * The south cardinal direction abbreviation.
- */
- private static final String SOUTH = "S";
-
- /**
- * The east cardinal direction abbreviation.
- */
- private static final String EAST = "E";
-
- /**
- * The west cardinal direction abbreviation.
- */
- private static final String WEST = "W";
-
- /**
- * The change location text.
- */
- private static final String CHANGE_LOCATION = "Change Location";
-
- /**
- * The color for the styled text for the example location.
- */
- private static final Color exampleColor = new Color(45, 100, 220);
-
- /**
- * The example location.
- */
- private static final String exampleChangeLocationText = Props.defaultLocation.getValue();
-
- /**
- * The styled example change location text.
- */
- private static final String styledExampleText = HtmlUtil.generateColoredHtmlText(
- exampleChangeLocationText, exampleColor);
-
- /**
- * The complete change location html styled text to show on the string getter's label.
- */
- private static final String changeLocationHtmlText = HtmlTags.openingHtml
- + "Enter your city, state (if applicable), and country code separated by a comma. Example: "
- + HtmlTags.breakTag + styledExampleText + HtmlTags.closingHtml;
-
- /**
- * The thread name for the weather stats updater.
- */
- private static final String WEATHER_STATS_UPDATER_THREAD_NAME = "Weather Stats Updater";
-
- /**
- * The thread name for the weather clock updater.
- */
- private static final String WEATHER_CLOCK_UPDATER_THREAD_NAME = "Weather Clock Updater";
-
- /**
- * The frequency to update the weather stats.
- */
- private static final Duration updateStatsFrequency = Duration.ofMinutes(5);
-
- /**
- * The frequency to check the exit condition for the stats updater.
- */
- private static final Duration checkUpdateStatsExitConditionFrequency = Duration.ofSeconds(10);
-
- /**
- * The last notification text following a location change attempt.
- */
- private String refreshingNotificationText;
-
- /**
- * The decimal formatter for the result.
- */
- private static final DecimalFormat floatMeasurementFormatter = new DecimalFormat("#.####");
-
- /**
- * Creates a new weather widget initialized to the user's current location.
- */
- private WeatherWidget() {
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * Shows a new weather widget instance.
- */
- @Widget(triggers = "weather", description = widgetDescription)
- public static void showGui() {
- getInstance().innerShowGui();
- }
-
- /**
- * Returns a new instance of the weather widget.
- *
- * @return a new instance of the weather widget
- */
- private static WeatherWidget getInstance() {
- WeatherWidget instance = new WeatherWidget();
- instances.add(instance);
- return instance;
- }
-
- /**
- * Shows the UI since we need to allow multiple instances of weather widget
- * while still having the public static showGui() method with the @Widget annotation.
- */
- private void innerShowGui() {
- if (NetworkUtil.isHighLatency()) {
- Console.INSTANCE.getConsoleCyderFrame().notify("Sorry, "
- + UserDataManager.INSTANCE.getUsername() + ", but this feature"
- + " is suspended until a stable internet connection can be established");
- return;
- } else if (!Props.weatherKey.valuePresent()) {
- Console.INSTANCE.getConsoleCyderFrame().inform("Sorry, but the Weather Key has"
- + " not been set or is invalid, as a result, many features of Cyder will not work as"
- + " intended. Please see the fields panel of the user editor to learn how to acquire"
- + " a key and set it.", "Weather Key Not Set");
- return;
- }
-
- repullWeatherStats();
-
- UiUtil.closeIfOpen(weatherFrame);
- weatherFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setBackgroundIconFromColor(CyderColors.regularBlue)
- .build();
- weatherFrame.addPreCloseAction(this::onWeatherFrameDisposed);
- weatherFrame.setBackground(defaultBackground);
- weatherFrame.setTitle(DEFAULT_TITLE);
-
- currentTimeLabel = new JLabel(getWeatherTimeAccountForGmtOffset(), SwingConstants.CENTER);
- currentTimeLabel.setForeground(CyderColors.navy);
- currentTimeLabel.setFont(CyderFonts.SEGOE_20);
- currentTimeLabel.setBounds(0, 50, 480, 30);
- weatherFrame.getContentPane().add(currentTimeLabel);
-
- locationLabel = new JLabel(currentLocationString, SwingConstants.CENTER);
- locationLabel.setForeground(CyderColors.navy);
- locationLabel.setFont(CyderFonts.SEGOE_20);
- locationLabel.setBounds(0, 85, 480, 30);
- weatherFrame.getContentPane().add(locationLabel);
-
- final int strokeWidth = 3;
-
- JLabel currentWeatherContainer = new JLabel() {
- private static final int arcLen = 25;
- private static final int offset = 10;
-
- @Override
- public void paint(Graphics g) {
- Graphics2D g2d = (Graphics2D) g;
- g.setColor(CyderColors.navy);
- g2d.setStroke(new BasicStroke(strokeWidth));
- g2d.fillRoundRect(offset, offset, 100, 160, arcLen, arcLen);
- super.paint(g);
- }
- };
- currentWeatherContainer.setBounds(180, 120, 120, 180);
- weatherFrame.getContentPane().add(currentWeatherContainer);
-
- currentWeatherIconLabel = new JLabel(generateCurrentWeatherIcon());
- currentWeatherIconLabel.setBounds(0, 25, currentWeatherContainer.getWidth(),
- currentWeatherContainer.getHeight() / 2);
- currentWeatherContainer.add(currentWeatherIconLabel);
-
- currentWeatherLabel = new JLabel("", SwingConstants.CENTER);
- currentWeatherLabel.setForeground(CyderColors.vanilla);
- currentWeatherLabel.setFont(CyderFonts.SEGOE_20.deriveFont(18f));
- currentWeatherLabel.setBounds(0, currentWeatherContainer.getHeight() / 2,
- currentWeatherContainer.getWidth(), currentWeatherContainer.getHeight() / 2);
- currentWeatherContainer.add(currentWeatherLabel);
-
- ImageIcon sunriseIcon = new ImageIcon(StaticUtil.getStaticPath("sunrise.png"));
- JLabel sunriseLabelIcon = new JLabel(sunriseIcon) {
- private static final int arcLen = 25;
- private static final int offset = 10;
-
- @Override
- public void paint(Graphics g) {
- Graphics2D g2d = (Graphics2D) g;
- g.setColor(CyderColors.navy);
- g2d.setStroke(new BasicStroke(strokeWidth));
- g2d.fillRoundRect(offset, offset, 100, 160, arcLen, arcLen);
- super.paint(g);
- }
- };
- sunriseLabelIcon.setBounds(60, 120, 120, 180);
- weatherFrame.getContentPane().add(sunriseLabelIcon);
-
- sunriseLabel = new JLabel(sunriseFormatted + AM, SwingConstants.CENTER);
- sunriseLabel.setForeground(CyderColors.vanilla);
- sunriseLabel.setFont(CyderFonts.SEGOE_20);
- sunriseLabel.setBounds(0, sunriseLabelIcon.getHeight() / 2, sunriseLabelIcon.getWidth(),
- sunriseLabelIcon.getHeight() / 2);
- sunriseLabelIcon.add(sunriseLabel);
-
- ImageIcon sunsetIcon = new ImageIcon(StaticUtil.getStaticPath("sunset.png"));
- JLabel sunsetLabelIcon = new JLabel(sunsetIcon) {
- private static final int arcLen = 25;
- private static final int offset = 10;
-
- @Override
- public void paint(Graphics g) {
- Graphics2D g2d = (Graphics2D) g;
- g.setColor(CyderColors.navy);
- ((Graphics2D) g).setStroke(new BasicStroke(strokeWidth));
- g2d.fillRoundRect(offset, offset, 100, 160, arcLen, arcLen);
- super.paint(g);
- }
- };
- sunsetLabelIcon.setBounds(480 - 60 - 120, 120, 120, 180);
- weatherFrame.getContentPane().add(sunsetLabelIcon);
-
- sunsetLabel = new JLabel(sunsetFormatted + PM, SwingConstants.CENTER);
- sunsetLabel.setForeground(CyderColors.vanilla);
- sunsetLabel.setFont(CyderFonts.SEGOE_20);
- sunsetLabel.setBounds(0, sunsetLabelIcon.getHeight() / 2, sunsetLabelIcon.getWidth(),
- sunsetLabelIcon.getHeight() / 2);
- sunsetLabelIcon.add(sunsetLabel);
-
- GetInputBuilder changeLocationBuilder = new GetInputBuilder(CHANGE_LOCATION, changeLocationHtmlText)
- .setRelativeTo(weatherFrame)
- .setSubmitButtonText(CHANGE_LOCATION)
- .setLabelFont(CyderFonts.DEFAULT_FONT_SMALL)
- .setInitialFieldText(currentLocationString)
- .setSubmitButtonColor(CyderColors.regularPurple);
-
- DragLabelTextButton locationButton = new DragLabelTextButton.Builder("Change Location")
- .setClickAction(() -> CyderThreadRunner.submit(() -> {
- getterUtilInstance.closeAllGetFrames();
- Optional optionalNewLocation = getterUtilInstance.getInput(changeLocationBuilder);
-
- try {
- if (optionalNewLocation.isEmpty()) return;
- String newLocation = optionalNewLocation.get();
- previousLocationString = currentLocationString;
- ArrayList parts = Arrays.stream(newLocation.split(CyderStrings.comma))
- .map(string -> StringUtil.capsFirstWords(string.trim()))
- .collect(Collectors.toCollection(ArrayList::new));
- currentLocationString = StringUtil.joinParts(parts, CyderStrings.comma);
- useCustomLoc = true;
-
- refreshingNotificationText = "Attempting to refresh weather stats for location "
- + CyderStrings.quote + currentLocationString + CyderStrings.quote;
- weatherFrame.notify(refreshingNotificationText);
-
- repullWeatherStats();
- } catch (Exception ex) {
- ExceptionHandler.handle(ex);
- }
- }, WEATHER_LOCATION_CHANGER_THREAD_NAME)).build();
-
- weatherFrame.getTopDragLabel().addLeftButton(locationButton, 0);
-
- minTempLabel = new JLabel();
- minTempLabel.setForeground(CyderColors.vanilla);
- minTempLabel.setFont(CyderFonts.DEFAULT_FONT_SMALL);
- weatherFrame.getContentPane().add(minTempLabel);
-
- maxTempLabel = new JLabel();
- maxTempLabel.setForeground(CyderColors.vanilla);
- maxTempLabel.setFont(CyderFonts.DEFAULT_FONT_SMALL);
-
- currentTempLabel = new JLabel();
- currentTempLabel.setForeground(CyderColors.regularPink);
- currentTempLabel.setFont(CyderFonts.DEFAULT_FONT_SMALL);
-
- customTempLabel = new JLabel() {
- private static final int borderLen = 3;
- private static final int componentHeight = 40;
-
- @Override
- public void paintComponent(Graphics g) {
- int w = customTempLabelWidth - 2 * borderLen;
- int h = componentHeight - 2 * borderLen;
- g.setColor(CyderColors.navy);
- g.fillRect(borderLen, borderLen, w, h);
-
- int mappedTemperatureValue = (int) Math.round(
- InterpolationUtil.rangeMap(temperature, minTemp, maxTemp, 0, customTempLabelWidth));
- int yOffset = 3;
- int lineWidth = 6;
- g.setColor(CyderColors.regularPink);
- g.fillRect(mappedTemperatureValue + yOffset, borderLen,
- lineWidth, componentHeight - 2 * yOffset);
-
- String minTempText = formatFloatMeasurement(minTemp) + "F";
- minTempLabel.setText(minTempText);
- minTempLabel.setSize(
- StringUtil.getMinWidth(minTempText, minTempLabel.getFont()),
- StringUtil.getMinHeight(minTempText, minTempLabel.getFont()));
- minTempLabel.setLocation(10, (componentHeight - minTempLabel.getHeight()) / 2);
- customTempLabel.add(minTempLabel);
-
- String currentTempText = formatFloatMeasurement(temperature) + "F";
- currentTempLabel.setText(currentTempText);
- currentTempLabel.setSize(
- StringUtil.getMinWidth(currentTempText, currentTempLabel.getFont()),
- StringUtil.getMinHeight(currentTempText, currentTempLabel.getFont()));
- currentTempLabel.setLocation(customTempLabel.getWidth() / 2 - currentTempLabel.getWidth() / 2,
- customTempLabel.getHeight() / 2 - currentTempLabel.getHeight() / 2);
- customTempLabel.add(currentTempLabel);
-
- // set max temp label
- String maxText = formatFloatMeasurement(maxTemp) + "F";
- maxTempLabel.setText(maxText);
- maxTempLabel.setSize(
- StringUtil.getMinWidth(maxText, minTempLabel.getFont()),
- StringUtil.getMinHeight(maxText, minTempLabel.getFont()));
- maxTempLabel.setLocation(customTempLabelWidth - maxTempLabel.getWidth(),
- (componentHeight - maxTempLabel.getHeight()) / 2);
- customTempLabel.add(maxTempLabel);
-
- g.setColor(Color.black);
-
- g.fillRect(0, 0, borderLen, componentHeight);
- g.fillRect(customTempLabelWidth - borderLen, 0, borderLen, componentHeight);
- g.fillRect(0, 0, customTempLabelWidth, borderLen);
- g.fillRect(0, componentHeight - borderLen, customTempLabelWidth, borderLen);
- }
- };
- customTempLabel.setBounds(40, 320, customTempLabelWidth, 40);
- weatherFrame.getContentPane().add(customTempLabel);
-
- windSpeedLabel = new JLabel("", SwingConstants.CENTER);
- windSpeedLabel.setText("Wind: " + windSpeed + Units.MILES_PER_HOUR.getAbbreviation()
- + comma + space + windBearing + Units.DEGREES.getAbbreviation() + space + openingParenthesis
- + getWindDirection(windBearing) + CyderStrings.closingParenthesis);
- windSpeedLabel.setForeground(CyderColors.navy);
- windSpeedLabel.setFont(CyderFonts.SEGOE_20);
- windSpeedLabel.setBounds(0, 390, 480, 30);
- weatherFrame.getContentPane().add(windSpeedLabel);
-
- windDirectionLabel = new JLabel() {
- private static final int length = 50;
- private static final int borderLength = 3;
- private static final int arrowWidth = 3;
- private static final int arrowRadius = 20;
-
- private static final Color backgroundColor = Color.black;
- private static final Color innerColor = CyderColors.navy;
- private static final Color arrowColor = CyderColors.regularPink;
-
- @Override
- public void paintComponent(Graphics g) {
- g.setColor(backgroundColor);
- g.fillRect(0, 0, length, length);
-
- g.setColor(innerColor);
- g.fillRect(borderLength, borderLength,
- getWidth() - 2 * borderLength, getHeight() - 2 * borderLength);
-
- double theta = windBearing * Math.PI / 180.0;
- double x = arrowRadius * Math.cos(theta);
- double y = arrowRadius * Math.sin(theta);
-
- int drawToX = (int) Math.round(x);
- int drawToY = -(int) Math.round(y);
-
- Graphics2D g2d = (Graphics2D) g;
- g2d.setStroke(new BasicStroke(arrowWidth));
-
- int w = getWidth();
- int h = getHeight();
-
- g.setColor(arrowColor);
- g.drawLine(w / 2, h / 2, w / 2 + drawToX, w / 2 + drawToY);
- }
- };
- windDirectionLabel.setBounds(weatherFrame.getWidth() / 2 - 50 / 2, 430, 50, 50);
- weatherFrame.getContentPane().add(windDirectionLabel);
-
- humidityLabel = new JLabel("Humidity: " + humidity + "%", SwingConstants.CENTER);
- humidityLabel.setForeground(CyderColors.navy);
- humidityLabel.setFont(CyderFonts.SEGOE_20);
- humidityLabel.setBounds(0, 500, 480, 30);
- weatherFrame.getContentPane().add(humidityLabel);
-
- pressureLabel = new JLabel("Pressure: " + pressure + Units.ATMOSPHERES.getAbbreviation(),
- SwingConstants.CENTER);
- pressureLabel.setForeground(CyderColors.navy);
- pressureLabel.setFont(CyderFonts.SEGOE_20);
- pressureLabel.setBounds(0, 540, 480, 30);
- weatherFrame.getContentPane().add(pressureLabel);
-
- timezoneLabel = new JLabel("Timezone: " + getGmtTimezoneLabelText(), SwingConstants.CENTER);
- timezoneLabel.setForeground(CyderColors.navy);
- timezoneLabel.setFont(CyderFonts.SEGOE_20);
- timezoneLabel.setBounds(0, 580, 480, 30);
- weatherFrame.getContentPane().add(timezoneLabel);
-
- weatherFrame.finalizeAndShow();
-
- startWeatherStatsUpdater();
- startUpdatingClock();
- }
-
- /**
- * The actions to invoke when this weather frame is disposed.
- */
- private void onWeatherFrameDisposed() {
- stopUpdating.set(true);
- instances.remove(this);
- getterUtilInstance.closeAllGetFrames();
- }
-
- /**
- * Starts the thread to update the current time label.
- */
- private void startUpdatingClock() {
- CyderThreadRunner.submit(() -> {
- while (!stopUpdating.get()) {
- ThreadUtil.sleep((long) TimeUtil.millisInSecond);
- currentTimeLabel.setText(getWeatherTimeAccountForGmtOffset());
- }
- }, WEATHER_CLOCK_UPDATER_THREAD_NAME);
- }
-
- /**
- * Starts the thread to update the weather stats.
- */
- private void startWeatherStatsUpdater() {
- CyderThreadRunner.submit(() -> {
- try {
- while (true) {
- ThreadUtil.sleepWithChecks(updateStatsFrequency.toMillis(),
- checkUpdateStatsExitConditionFrequency.toMillis(), stopUpdating);
- if (stopUpdating.get()) break;
- repullWeatherStats();
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, WEATHER_STATS_UPDATER_THREAD_NAME);
- }
-
- /**
- * Returns the current weather time correct based on the current gmt offset.
- *
- * @return the current weather time correct based on the current gmt offset
- */
- private String getWeatherTimeAccountForGmtOffset() {
- Calendar calendar = Calendar.getInstance();
- SimpleDateFormat dateFormatter = TimeUtil.weatherFormat;
- dateFormatter.setTimeZone(TimeZone.getTimeZone(GMT));
-
- try {
- int timeOffset = Integer.parseInt(weatherDataGmtOffset) / SECONDS_IN_HOUR;
- calendar.add(Calendar.HOUR, timeOffset);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- return dateFormatter.format(calendar.getTime());
- }
-
- /**
- * Refreshes the weather labels based off of the current vars.
- */
- private void refreshWeatherLabels() {
- if (currentLocationString.length() > 1) {
- String[] parts = currentLocationString.split(CyderStrings.comma);
- StringBuilder sb = new StringBuilder();
-
- for (int i = 0 ; i < parts.length ; i++) {
- String part = parts[i].trim();
-
- boolean properLength = parts.length == cityStateCountryFormatLen;
- boolean isState = i == stateIndex;
- boolean stateAbbreviationLength = part.length() == stateAbbrLen;
- if (properLength && isState && stateAbbreviationLength) {
- sb.append(part.toUpperCase());
- } else {
- sb.append(StringUtil.capsFirstWords(part));
- }
-
- if (i != parts.length - 1) sb.append(", ");
- }
-
- locationLabel.setText(sb.toString());
- } else {
- locationLabel.setText("");
- }
-
- currentWeatherIconLabel.setIcon(generateCurrentWeatherIcon());
-
- currentWeatherLabel.setText(HtmlTags.openingHtml
- + HtmlTags.divTextAlignCenterVerticalAlignBottom
- + StringUtil.capsFirstWords(weatherCondition)
- .replaceAll(CyderRegexPatterns.whiteSpaceRegex, HtmlTags.breakTag)
- + HtmlTags.closingHtml);
-
- windSpeedLabel.setText("Wind" + colon + space + windSpeed + Units.MILES_PER_HOUR.getAbbreviation()
- + CyderStrings.comma + space + windBearing + Units.DEGREES.getAbbreviation() + space
- + CyderStrings.openingParenthesis + getWindDirection(windBearing)
- + CyderStrings.closingParenthesis);
- humidityLabel.setText("Humidity: " + humidity + "%");
- pressureLabel.setText("Pressure: " + formatFloatMeasurement(pressure) + Units.ATMOSPHERES.getAbbreviation());
- timezoneLabel.setText("Timezone: " + getGmtTimezoneLabelText());
-
- String sunriseMeridiemModifier = sunriseHour < 12 ? AM : PM;
- String sunsetMeridiemModifier = sunsetHour >= 12 ? AM : PM;
-
- sunriseLabel.setText(formatTimeAccountingForGmtOffset(sunriseFormatted) + sunriseMeridiemModifier);
- sunsetLabel.setText(formatTimeAccountingForGmtOffset(sunsetFormatted) + sunsetMeridiemModifier);
-
- customTempLabel.repaint();
- currentTempLabel.setText(temperature + "F");
-
- int tempLabelWidth = StringUtil.getMinWidth(currentTempLabel.getText(), currentTempLabel.getFont());
- int tempLabelHeight = StringUtil.getMinHeight(currentTempLabel.getText(), currentTempLabel.getFont());
-
- int tempLabelPadding = 3;
- currentTempLabel.setBounds(calculateTemperatureLineCenter(temperature, minTemp, maxTemp),
- customTempLabel.getY() - tempLabelPadding - tempLabelHeight, tempLabelWidth, tempLabelHeight);
-
- windDirectionLabel.repaint();
-
- String splitCity = currentLocationString.split(CyderStrings.comma)[0];
- refreshFrameTitle(splitCity);
-
- if (weatherFrame != null) {
- weatherFrame.revokeAllNotifications();
- weatherFrame.toast(new NotificationBuilder(REFRESHED).setViewDuration(1000));
- }
- }
-
- /**
- * Returns an ImageIcon for the current weather state.
- *
- * @return an ImageIcon for the current weather state
- */
- private ImageIcon generateCurrentWeatherIcon() {
- long sunsetTime = new Date(sunsetMillis * 1000).getTime();
- long currentTime = new Date().getTime();
-
- boolean isAfterSunset = currentTime > sunsetTime;
- String weatherIconIdAndTime = weatherIconId.replaceAll(CyderRegexPatterns.englishLettersRegex, "")
- + (isAfterSunset ? NIGHT_IMAGE_ID : DAY_IMAGE_ID);
-
- return StaticUtil.getImageIcon(weatherIconIdAndTime + Extension.PNG.getExtension());
- }
-
- /**
- * Calculates the x center for the current temperature within the temperature label.
- *
- * @param temperature the current temperature
- * @param minTemp the minimum temperature
- * @param maxTemp the maximum temperature
- * @return the x center for the current temperature within the temperature label
- */
- private int calculateTemperatureLineCenter(float temperature, float minTemp, float maxTemp) {
- int tempLabelWidth = StringUtil.getMinWidth(currentTempLabel.getText(), currentTempLabel.getFont());
-
- int customTempLabelMinX = customTempLabel.getX();
- int customTempLabelMaxX = customTempLabel.getX() + customTempLabel.getWidth() - tempLabelWidth;
-
- int temperatureLineCenter = (int) Math.ceil(customTempLabel.getX() + InterpolationUtil.rangeMap(
- temperature, minTemp, maxTemp, 0, customTempLabelWidth)) + temperatureLineCenterAdditive;
- temperatureLineCenter -= (tempLabelWidth) / 2;
-
- if (temperatureLineCenter < customTempLabelMinX) {
- temperatureLineCenter = customTempLabelMinX;
- }
-
- if (temperatureLineCenter > customTempLabelMaxX) {
- temperatureLineCenter = customTempLabelMaxX;
- }
-
- return temperatureLineCenter;
- }
-
- /**
- * Refreshes the frame title based on the provided city.
- *
- * @param city the city to display in the frame title
- */
- private void refreshFrameTitle(String city) {
- Preconditions.checkNotNull(city);
-
- city = city.trim();
-
- if (!city.isEmpty()) {
- String correctedCityName = StringUtil.capsFirstWords(city).trim();
- weatherFrame.setTitle(correctedCityName + StringUtil.getApostropheSuffix(correctedCityName)
- + CyderStrings.space + WEATHER);
- } else {
- weatherFrame.setTitle(DEFAULT_TITLE);
- }
- }
-
- /**
- * Returns the text for the timezone label. For example, if weatherDataGmtOffset is -18000
- * and DST is active, then the method will return "GMT-5 [DST Active].
- *
- * @return the text for the timezone label
- */
- private String getGmtTimezoneLabelText() {
- IpData data = IpDataManager.INSTANCE.getIpData();
-
- String gmtPart = GMT + (Integer.parseInt(weatherDataGmtOffset) / SECONDS_IN_HOUR);
- String dstPart = data.getTime_zone().isIs_dst() ?
- CyderStrings.space + CyderStrings.openingBracket + DST_ACTIVE + CyderStrings.closingBracket : "";
-
- return gmtPart + dstPart;
- }
-
- /**
- * Returns the hh:mm time after accounting for the GMT offset.
- *
- * @param absoluteTime the absolute hh:mm time
- * @return the hh:mm time after accounting for the GMT offset
- */
- private String formatTimeAccountingForGmtOffset(String absoluteTime) {
- Preconditions.checkNotNull(absoluteTime);
- Preconditions.checkArgument(absoluteTime.contains(colon));
-
- String[] splitTime = absoluteTime.split(colon);
- Preconditions.checkState(splitTime.length == 2);
-
- int hour = Integer.parseInt(splitTime[0]);
- int minute = Integer.parseInt(splitTime[1]);
-
- hour += (Integer.parseInt(weatherDataGmtOffset) / SECONDS_IN_HOUR - (parsedGmtOffset / SECONDS_IN_HOUR));
-
- return hour + colon + formatMinutes(minute);
- }
-
- /**
- * Formats the provided minutes to always have two digits.
- *
- * @param minute the minutes value
- * @return the formatted minutes string
- */
- private String formatMinutes(int minute) {
- Preconditions.checkArgument(TimeUtil.minuteRange.contains(minute));
-
- return minute < 10 ? "0" + minute : String.valueOf(minute);
- }
-
- /**
- * Refreshes the weather stat variables.
- */
- private void repullWeatherStats() {
- CyderThreadRunner.submit(() -> {
- IpData data = IpDataManager.INSTANCE.getIpData();
-
- userCity = data.getCity();
- userState = data.getRegion();
- userCountry = data.getCountry_name();
-
- if (!useCustomLoc) currentLocationString = userCity + ", " + userState + ", " + userCountry;
-
- Optional optionalWeatherData = WeatherUtil.getWeatherData(currentLocationString);
- if (optionalWeatherData.isEmpty()) {
- weatherFrame.revokeNotification(refreshingNotificationText);
- weatherFrame.notify("Sorry, but that location is invalid");
- currentLocationString = previousLocationString;
- useCustomLoc = false;
- return;
- }
-
- WeatherData weatherData = optionalWeatherData.get();
- sunriseMillis = Long.parseLong(String.valueOf(weatherData.getSys().getSunrise()));
- sunsetMillis = Long.parseLong(String.valueOf(weatherData.getSys().getSunset()));
- weatherIconId = weatherData.getWeather().get(0).getIcon();
- windSpeed = weatherData.getWind().getSpeed();
- windBearing = weatherData.getWind().getDeg();
- weatherCondition = weatherData.getWeather().get(0).getDescription();
- pressure = weatherData.getMain().getPressure();
- humidity = weatherData.getMain().getHumidity();
- temperature = weatherData.getMain().getTemp();
- weatherDataGmtOffset = String.valueOf(weatherData.getTimezone());
- minTemp = weatherData.getMain().getTemp_min();
- maxTemp = weatherData.getMain().getTemp_max();
-
- refreshMapBackground();
-
- Date sunrise = new Date((long) (sunriseMillis * TimeUtil.millisInSecond));
- sunriseFormatted = sunriseSunsetFormat.format(sunrise);
- Calendar sunriseCalendar = GregorianCalendar.getInstance();
- sunriseCalendar.setTimeInMillis(sunriseMillis);
- sunriseHour = sunriseCalendar.get(Calendar.HOUR);
-
- Date sunset = new Date((long) (sunsetMillis * TimeUtil.millisInSecond));
- sunsetFormatted = sunriseSunsetFormat.format(sunset);
- Calendar sunsetCalendar = GregorianCalendar.getInstance();
- sunsetCalendar.setTimeInMillis(sunsetMillis);
- sunsetHour = sunsetCalendar.get(Calendar.HOUR);
-
- if (!isGmtSet) {
- parsedGmtOffset = Integer.parseInt(weatherDataGmtOffset);
- isGmtSet = true;
- }
-
- refreshWeatherLabels();
-
- Console.INSTANCE.revalidateConsoleTaskbarMenu();
- }, WEATHER_STATS_UPDATER_THREAD_NAME);
- }
-
- /**
- * Refreshes the map background of the weather frame. If not enabled, hides the map.
- * If enabled, shows the map.
- */
- public void refreshMapBackground() {
- try {
- if (UserDataManager.INSTANCE.shouldDrawWeatherMap()) {
- ImageIcon newMapBackground = mapViewBuilder.setLocationString(currentLocationString).getMapView();
- weatherFrame.setBackground(newMapBackground);
- } else {
- weatherFrame.setBackground(defaultBackground);
- }
-
- refreshReadableLabels(UserDataManager.INSTANCE.shouldDrawWeatherMap());
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- weatherFrame.notify("Could not refresh map background");
- }
- }
-
- /**
- * Refreshes the labels with raw text on them based on the current visibility of the background map.
- *
- * @param mapVisible whether the map is visible
- */
- private void refreshReadableLabels(boolean mapVisible) {
- if (mapVisible) {
- currentTimeLabel.setForeground(CyderColors.navy);
- locationLabel.setForeground(CyderColors.navy);
- windSpeedLabel.setForeground(CyderColors.navy);
- humidityLabel.setForeground(CyderColors.navy);
- pressureLabel.setForeground(CyderColors.navy);
- timezoneLabel.setForeground(CyderColors.navy);
- } else {
- currentTimeLabel.setForeground(CyderColors.vanilla);
- locationLabel.setForeground(CyderColors.vanilla);
- windSpeedLabel.setForeground(CyderColors.vanilla);
- humidityLabel.setForeground(CyderColors.vanilla);
- pressureLabel.setForeground(CyderColors.vanilla);
- timezoneLabel.setForeground(CyderColors.vanilla);
- }
- }
-
- /**
- * Refreshes the map background of all weather instances.
- */
- public static void refreshAllMapBackgrounds() {
- instances.forEach(WeatherWidget::refreshMapBackground);
- }
-
- /**
- * Returns the wind direction string based off of the current wind bearing.
- *
- * @param bearing the current wind bearing
- * @return the wind direction string based off of the current wind bearing
- */
- public String getWindDirection(double bearing) {
- bearing = AngleUtil.normalizeAngle360(bearing);
-
- StringBuilder ret = new StringBuilder();
-
- if (AngleUtil.angleInNorthernHemisphere(bearing)) {
- ret.append(NORTH);
-
- if (bearing > AngleUtil.NINETY_DEGREES) {
- ret.append(WEST);
- } else if (bearing < AngleUtil.NINETY_DEGREES) {
- ret.append(EAST);
- }
- } else if (AngleUtil.angleInSouthernHemisphere(bearing)) {
- ret.append(SOUTH);
-
- if (bearing < AngleUtil.TWO_SEVENTY_DEGREES) {
- ret.append(WEST);
- } else if (bearing > AngleUtil.TWO_SEVENTY_DEGREES) {
- ret.append(EAST);
- }
- } else if (AngleUtil.angleIsEast(bearing)) {
- ret.append(EAST);
- } else if (AngleUtil.angleIsWest(bearing)) {
- ret.append(WEST);
- }
-
- return ret.toString();
- }
-
- /**
- * Returns the float formatted using {@link #floatMeasurementFormatter}.
- *
- * @param measurement the float measurement to format
- * @return the formatted measurement
- */
- private static String formatFloatMeasurement(float measurement) {
- return floatMeasurementFormatter.format(measurement);
- }
-}
diff --git a/src/main/java/cyder/widgets/CalculatorWidget.java b/src/main/java/cyder/widgets/CalculatorWidget.java
deleted file mode 100644
index 8e4dcece5..000000000
--- a/src/main/java/cyder/widgets/CalculatorWidget.java
+++ /dev/null
@@ -1,314 +0,0 @@
-package cyder.widgets;
-
-import com.fathzer.soft.javaluator.DoubleEvaluator;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.ui.button.CyderModernButton;
-import cyder.ui.button.ThemeBuilder;
-import cyder.ui.drag.CyderDragLabel;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-
-/**
- * A calculator widget for parsing mathematical expressions.
- */
-@Vanilla
-@CyderAuthor
-public final class CalculatorWidget {
- /**
- * The field to display the most recent results in.
- */
- private static CyderTextField resultField;
-
- /**
- * The field in which the user may enter an expression
- */
- private static CyderTextField calculatorField;
-
- /**
- * The text to display to user if an expression could not be parsed.
- */
- private static final String ERROR_TEXT = "Could not parse expression";
-
- /**
- * The font to use for the results field.
- */
- private static final Font fieldFont = new Font("Agency FB", Font.BOLD, 25);
-
- /**
- * The theme for each calculator button.
- */
- private static final ThemeBuilder theme = new ThemeBuilder();
-
- static {
- theme.setFont(CyderFonts.SEGOE_30);
- theme.setBorderLength(5);
- theme.setBackgroundColor(CyderColors.regularOrange);
- theme.setHoverColor(CyderColors.regularOrange.darker());
- theme.setPressedColor(CyderColors.regularOrange.darker().darker());
- }
-
- /**
- * Suppress default constructor.
- */
- private CalculatorWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The width of the calculator frame.
- */
- private static final int FRAME_WIDTH = 400;
-
- /**
- * The height of the calculator frame.
- */
- private static final int FRAME_HEIGHT = 600;
-
- /**
- * The width and height of each calculator button.
- */
- private static final int buttonLength = 75;
-
- /**
- * The description for the widget annotation.
- */
- private static final String description = "A calculator widget capable of "
- + "performing complex expressions such as e^x, sin(x), cos(x), and so forth.";
-
- @Widget(triggers = {"calculator", "calc", "math"}, description = description)
- public static void showGui() {
- CyderFrame calculatorFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle("Calculator")
- .build();
- calculatorFrame.setTitle("Calculator");
-
- resultField = new CyderTextField();
- resultField.setBorder(null);
- resultField.setEditable(false);
- resultField.setFocusable(true);
- resultField.setSelectionColor(CyderColors.selectionColor);
- resultField.setHorizontalAlignment(JTextField.RIGHT);
- resultField.setFont(fieldFont);
- resultField.setBounds(25, CyderDragLabel.DEFAULT_HEIGHT + 10, 350, 30);
- calculatorFrame.getContentPane().add(resultField);
-
- calculatorField = new CyderTextField();
- calculatorField.setBorder(null);
- calculatorField.setHorizontalAlignment(JTextField.LEFT);
- calculatorField.setSelectionColor(CyderColors.selectionColor);
- calculatorField.setToolTipText("Use radians and not degrees for any trig functions");
- calculatorField.setFont(fieldFont);
- calculatorField.setBounds(25,
- CyderDragLabel.DEFAULT_HEIGHT + 5 + 30 + 5, 350, 25);
- calculatorFrame.getContentPane().add(calculatorField);
-
- JLabel borderLabel = new JLabel();
- borderLabel.setBounds(20, CyderDragLabel.DEFAULT_HEIGHT + 5, 360, 65);
- borderLabel.setBorder(new LineBorder(CyderColors.navy, 5));
- borderLabel.setOpaque(false);
- calculatorFrame.getContentPane().add(borderLabel);
-
- CyderModernButton calculatorAdd = new CyderModernButton("+");
- calculatorAdd.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "+"));
- calculatorAdd.setTheme(theme);
- calculatorAdd.setBounds(20, 120, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorAdd);
-
- CyderModernButton calculatorSubtract = new CyderModernButton(CyderStrings.dash);
- calculatorSubtract.addClickRunnable(() -> calculatorField.setText(calculatorField.getText()
- + CyderStrings.dash));
- calculatorSubtract.setTheme(theme);
- calculatorSubtract.setBounds(115, 120, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorSubtract);
-
- CyderModernButton calculatorMultiply = new CyderModernButton("*");
- calculatorMultiply.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "*"));
- calculatorMultiply.setTheme(theme);
- calculatorMultiply.setBounds(210, 120, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorMultiply);
-
- CyderModernButton calculatorDivide = new CyderModernButton(CyderStrings.forwardSlash);
- calculatorDivide.addClickRunnable(() -> calculatorField.setText(calculatorField.getText()
- + CyderStrings.forwardSlash));
- calculatorDivide.setTheme(theme);
- calculatorDivide.setBounds(305, 120, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorDivide);
-
- CyderModernButton calculatorSeven = new CyderModernButton("7");
- calculatorSeven.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "7"));
- calculatorSeven.setTheme(theme);
- calculatorSeven.setBounds(20, 215, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorSeven);
-
- CyderModernButton calculatorEight = new CyderModernButton("8");
- calculatorEight.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "8"));
- calculatorEight.setBounds(115, 215, buttonLength, buttonLength);
- calculatorEight.setTheme(theme);
- calculatorFrame.getContentPane().add(calculatorEight);
-
- CyderModernButton calculatorNine = new CyderModernButton("9");
- calculatorNine.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "9"));
- calculatorNine.setTheme(theme);
- calculatorNine.setBounds(210, 215, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorNine);
-
- CyderModernButton calculatorEquals = new CyderModernButton("=");
- calculatorEquals.addClickRunnable(CalculatorWidget::computeExpression);
- calculatorEquals.setTheme(theme);
- calculatorEquals.setBounds(305, 215, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorEquals);
-
- CyderModernButton calculatorFour = new CyderModernButton("4");
- calculatorFour.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "4"));
- calculatorFour.setTheme(theme);
- calculatorFour.setBounds(20, 310, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorFour);
-
- CyderModernButton calculatorFive = new CyderModernButton("5");
- calculatorFive.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "5"));
- calculatorFive.setTheme(theme);
- calculatorFive.setBounds(115, 310, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorFive);
-
- CyderModernButton calculatorSix = new CyderModernButton("6");
- calculatorSix.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "6"));
- calculatorSix.setTheme(theme);
- calculatorSix.setBounds(210, 310, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorSix);
-
- CyderModernButton calculatorClear = new CyderModernButton("CE");
- calculatorClear.addClickRunnable(CalculatorWidget::clearFields);
- calculatorClear.setTheme(theme);
- calculatorClear.setBounds(305, 310, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorClear);
-
- CyderModernButton calculatorOne = new CyderModernButton("1");
- calculatorOne.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "1"));
- calculatorOne.setTheme(theme);
- calculatorOne.setBounds(20, 405, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorOne);
-
- CyderModernButton calculatorTwo = new CyderModernButton("2");
- calculatorTwo.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "2"));
- calculatorTwo.setTheme(theme);
- calculatorTwo.setBounds(115, 405, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorTwo);
-
- CyderModernButton calculatorThree = new CyderModernButton("3");
- calculatorThree.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "3"));
- calculatorThree.setTheme(theme);
- calculatorThree.setBounds(210, 405, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorThree);
-
- CyderModernButton undo = new CyderModernButton("<<");
- undo.addClickRunnable(CalculatorWidget::undoAction);
- undo.setTheme(theme);
- undo.setBounds(305, 405, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(undo);
-
- CyderModernButton calculatorZero = new CyderModernButton("0");
- calculatorZero.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "0"));
- calculatorZero.setTheme(theme);
- calculatorZero.setBounds(20, 500, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorZero);
-
- CyderModernButton calculatorDecimal = new CyderModernButton(".");
- calculatorDecimal.addClickRunnable(() -> calculatorField.setText(calculatorField.getText() + "."));
- calculatorDecimal.setTheme(theme);
- calculatorDecimal.setBounds(115, 500, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorDecimal);
-
- CyderModernButton calculatorOpenP = new CyderModernButton(CyderStrings.openingParenthesis);
- calculatorOpenP.addClickRunnable(() -> calculatorField.setText(calculatorField.getText()
- + CyderStrings.openingParenthesis));
- calculatorOpenP.setTheme(theme);
- calculatorOpenP.setBounds(210, 500, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorOpenP);
-
- CyderModernButton calculatorCloseP = new CyderModernButton(CyderStrings.closingParenthesis);
- calculatorCloseP.addClickRunnable(() -> calculatorField.setText(calculatorField.getText()
- + CyderStrings.closingParenthesis));
- calculatorCloseP.setTheme(theme);
- calculatorCloseP.setBounds(305, 500, buttonLength, buttonLength);
- calculatorFrame.getContentPane().add(calculatorCloseP);
-
- calculatorFrame.finalizeAndShow();
- }
-
- /**
- * Clears the calculator fields.
- */
- private static void clearFields() {
- calculatorField.setText("");
- resultField.setText("");
- }
-
- /**
- * Removes the last character from the calculator field.
- */
- private static void undoAction() {
- String text = calculatorField.getText();
-
- if (text.length() > 0) {
- calculatorField.setText(text.substring(0, text.length() - 1));
- }
- }
-
- /**
- * The evaluator for evaluating expressions.
- */
- private static final DoubleEvaluator evaluator = new DoubleEvaluator();
-
- /**
- * The positive infinity string.
- */
- private static final String POSITIVE_INFINITY = "+∞";
-
- /**
- * The negative infinity string.
- */
- private static final String NEGATIVE_INFINITY = "-∞";
-
- /**
- * Attempts to compute the expression from the calculator field.
- */
- private static void computeExpression() {
- try {
- double result = evaluator.evaluate(calculatorField.getText().trim());
- String resultString = String.valueOf(result);
-
- if (result == Double.POSITIVE_INFINITY) {
- resultString = POSITIVE_INFINITY;
- } else if (result == Double.NEGATIVE_INFINITY) {
- resultString = NEGATIVE_INFINITY;
- }
-
- setResultText(resultString);
- } catch (IllegalArgumentException e) {
- setResultText(ERROR_TEXT);
- }
- }
-
- /**
- * Animates in the results text to the results field by fading it from
- * {@link CyderColors#regularRed} to {@link CyderColors#navy} in 500ms.
- *
- * @param resultText the text to show in the results field
- */
- private synchronized static void setResultText(String resultText) {
- resultField.setText(resultText);
- resultField.flashField();
- }
-}
diff --git a/src/main/java/cyder/widgets/ClickWidget.java b/src/main/java/cyder/widgets/ClickWidget.java
deleted file mode 100644
index 91cd69b87..000000000
--- a/src/main/java/cyder/widgets/ClickWidget.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package cyder.widgets;
-
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.math.NumberUtil;
-import cyder.strings.CyderStrings;
-import cyder.ui.UiUtil;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.FrameType;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-/**
- * A widget for extreme boredom.
- */
-@Vanilla
-@CyderAuthor
-public final class ClickWidget {
- /**
- * Suppress default instantiation.
- */
- private ClickWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The frame title and label text.
- */
- private static final String CLICK_ME = "Click Me";
-
- /**
- * The frame width.
- */
- private static final int FRAME_WIDTH = 220;
-
- /**
- * The frame height.
- */
- private static final int FRAME_HEIGHT = 100;
-
- /**
- * The widget frame.
- */
- private static CyderFrame clickMeFrame;
-
- /**
- * The offset between the monitor bounds and the possible locations to place the frame at.
- */
- private static final int monitorMinOffset = 200;
-
- /**
- * The font for the click me label.
- */
- private static final Font clickMeLabelFont = new Font(CyderFonts.SEGOE_UI_BLACK, Font.BOLD, 22);
-
- @Widget(triggers = "click me", description = "A troll widget that pops open a new window every time it is clicked")
- public static void showGui() {
- try {
- UiUtil.closeIfOpen(clickMeFrame);
-
- clickMeFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(CLICK_ME)
- .setBackgroundColor(CyderColors.vanilla)
- .setType(FrameType.POPUP)
- .build();
- clickMeFrame.setAutoFastClose(true);
-
- JLabel clickMeLabel = new JLabel(CLICK_ME);
- clickMeLabel.setHorizontalAlignment(JLabel.CENTER);
- clickMeLabel.setVerticalAlignment(JLabel.CENTER);
- clickMeLabel.setForeground(CyderColors.navy);
- clickMeLabel.setFont(clickMeLabelFont);
- clickMeLabel.setBounds(30, 40, 150, 40);
- clickMeLabel.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseReleased(MouseEvent e) {
- changeFramePosition();
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- clickMeLabel.setForeground(CyderColors.regularRed);
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- clickMeLabel.setForeground(CyderColors.navy);
- }
- });
-
- clickMeFrame.getContentPane().add(clickMeLabel);
-
- clickMeFrame.finalizeAndShow();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
-
- /**
- * The logic for when the click me label is pressed.
- */
- @ForReadability
- private static void changeFramePosition() {
- Rectangle bounds = clickMeFrame.getMonitorBounds();
- int minX = (int) bounds.getMinX();
- int maxX = (int) (minX + bounds.getHeight());
- int minY = (int) bounds.getMinY();
- int maxY = (int) (minY + bounds.getHeight());
-
- int randomX = NumberUtil.generateRandomInt(minX + monitorMinOffset, maxX - monitorMinOffset);
- int randomY = NumberUtil.generateRandomInt(minY + monitorMinOffset, maxY - monitorMinOffset);
-
- clickMeFrame.setLocation(randomX, randomY);
- }
-}
diff --git a/src/main/java/cyder/widgets/ClockWidget.java b/src/main/java/cyder/widgets/ClockWidget.java
deleted file mode 100644
index d344555d7..000000000
--- a/src/main/java/cyder/widgets/ClockWidget.java
+++ /dev/null
@@ -1,874 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.constants.HtmlTags;
-import cyder.exceptions.IllegalMethodException;
-import cyder.getter.GetInputBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.math.AngleUtil;
-import cyder.network.IpDataManager;
-import cyder.parsers.ip.IpData;
-import cyder.props.Props;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.time.TimeUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.drag.CyderDragLabel;
-import cyder.ui.drag.button.DragLabelTextButton;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.TitlePosition;
-import cyder.ui.label.CyderLabel;
-import cyder.user.UserDataManager;
-import cyder.utils.ColorUtil;
-import cyder.weather.WeatherUtil;
-import cyder.weather.parsers.Coord;
-import cyder.weather.parsers.WeatherData;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.text.SimpleDateFormat;
-import java.time.Duration;
-import java.util.Calendar;
-import java.util.Optional;
-import java.util.TimeZone;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static cyder.strings.CyderStrings.*;
-
-/**
- * A clock widget for displaying the current time in a fancy and minimalistic format.
- */
-@Vanilla
-@CyderAuthor
-public final class ClockWidget {
- /**
- * Suppress default constructor.
- */
- private ClockWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The clock frame.
- */
- private static CyderFrame clockFrame;
-
- /**
- * The custom label to paint.
- */
- private static JLabel clockLabel;
-
- /**
- * The digital time label.
- */
- private static JLabel digitalTimeAndDateLabel;
-
- /**
- * Whether to show the seconds hand
- */
- private static boolean showSecondHand = true;
-
- /**
- * Whether to show the hour numerals.
- */
- private static boolean paintHourLabels = true;
-
- /**
- * The default clock color
- */
- private static Color clockColor = CyderColors.getGuiThemeColor();
-
- /**
- * Whether to update the clock.
- */
- private static final AtomicBoolean shouldUpdateWidget = new AtomicBoolean(false);
-
- /**
- * The default location for the clock.
- */
- private static final String DEFAULT_LOCATION = "Greenwich, London";
-
- /**
- * The GMT location string.
- */
- private static String currentLocation = DEFAULT_LOCATION;
-
- /**
- * The GMT offset for the current timezone.
- */
- private static int currentGmtOffset;
-
- /**
- * The taskbar button text to spawn a mini clock frame.
- */
- private static final String MINI = "Mini";
-
- /**
- * The tooltip for the mini button.
- */
- private static final String TOOLTIP = "Spawn a mini clock for the current location";
-
- /**
- * The description of this widget.
- */
- private static final String widgetDescription = "A clock widget capable of spawning"
- + " mini widgets and changing the time zone";
-
- /**
- * A joiner for joining strings on commas.
- */
- private static final Joiner commaJoiner = Joiner.on(CyderStrings.comma);
-
- /**
- * The list of roman numerals, organized by the angle made between the positive x axis.
- */
- private static final ImmutableList romanNumerals = ImmutableList.of(
- "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "I", "II"
- );
-
- /**
- * The widget frame title.
- */
- private static final String CLOCK = "Clock";
-
- /**
- * The frame width of the widget.
- */
- private static final int FRAME_WIDTH = 500;
-
- /**
- * The frame height of the widget.
- */
- private static final int FRAME_HEIGHT = 600;
-
- /**
- * The hour date pattern.
- */
- private static final String hourDaterPattern = "HH";
-
- /**
- * The minute date pattern.
- */
- private static final String minuteDatePattern = "mm";
-
- /**
- * The second date pattern.
- */
- private static final String secondDatePattern = "ss";
-
- /**
- * The font of the clock label.
- */
- private static final Font clockFont = new Font(CyderFonts.AGENCY_FB, Font.BOLD, 26);
-
- /**
- * The y padding for the digital time and date label.
- */
- private static final int digitalTimeAndDateLabelYPadding = 20;
-
- /**
- * The x padding for the digital time and date label.
- */
- private static final int digitalTimeAndDateLabelXPadding = 10;
-
- /**
- * The clock label padding between the label ends and the frame.
- */
- private static final int clockLabelPadding = 20;
-
- /**
- * The length of the clock label.
- */
- private static final int clockLabelLength = FRAME_WIDTH - 2 * clockLabelPadding;
-
- /**
- * The hour hand ratio for the radius.
- */
- private static final float hourHandRatio = 0.65f;
-
- /**
- * The minute hand ratio for the radius.
- */
- private static final float minuteHandRatio = 0.75f;
-
- /**
- * The second hand ratio for the radius.
- */
- private static final float secondHandRatio = 0.80f;
-
- /**
- * The radius of the center dot.
- */
- private static final int centerDotRadius = 20;
-
- /**
- * The additive for the starting y values of numeral labels.
- */
- private static final int numeralLabelTopLeftYAdditive = -10;
-
- /**
- * The length of hour box labels.
- */
- private static final int hourBoxLabelLength = 20;
-
- /**
- * The padding between the edges of the clock label and painted attributes.
- */
- private static final int innerLabelPadding = 20;
-
- /**
- * The maximum radius for clock hands.
- */
- private static final int maxHandRadius = (clockLabelLength - innerLabelPadding * 2 - hourBoxLabelLength * 2) / 2;
-
- /**
- * The center of the clock label.
- */
- private static final int clockLabelCenter = clockLabelLength / 2;
-
- /**
- * The increment for painting hours.
- */
- private static final double hourThetaInc = AngleUtil.THREE_SIXTY_DEGREES / romanNumerals.size();
-
- /**
- * The radius for the hour hand.
- */
- private static final int hourHandRadius = (int) (maxHandRadius * hourHandRatio);
-
- /**
- * The radius for the minute hand.
- */
- private static final int minuteHandRadius = (int) (maxHandRadius * minuteHandRatio);
-
- /**
- * The radius for the second hand.
- */
- private static final int secondHandRadius = (int) (maxHandRadius * secondHandRatio);
-
- /**
- * The location string.
- */
- private static final String LOCATION = "Location";
-
- /**
- * The current location string.
- */
- private static final String CURRENT_LOCATION = "Current Location";
-
- /**
- * The set location string.
- */
- private static final String SET_LOCATION = "Set location";
-
- /**
- * The label text for the getter util for setting the current location.
- */
- private static final String locationLabelText = "Time Location "
- + HtmlTags.breakTag + "Enter locations separated by commas";
-
- /**
- * The color string.
- */
- private static final String COLOR = "Color";
-
- /**
- * The theme color string.
- */
- private static final String THEME_COLOR = "Theme color";
-
- /**
- * The regex for the get string color getter.
- */
- private static final String colorThemeFieldRegex = "[A-Fa-f0-9]{0,6}";
-
- /**
- * The name for the color theme color getter waiting thread.
- */
- private static final String CLOCK_COLOR_THEME_GETTER_WAITER = "Clock Color Theme Getter";
-
- /**
- * The thread name for the clock widget initializer thread.
- */
- private static final String CLOCK_WIDGET_INITIALIZER_THREAD_NAME = "Clock Widget Initializer";
-
- /**
- * The width of mini frames to spawn.
- */
- private static final int miniFrameWidth = 600;
-
- /**
- * The height of mini frames to spawn.
- */
- private static final int miniFrameHeight = 150;
-
- /**
- * The timezone colon text.
- */
- private static final String TIMEZONE = "Timezone:";
-
- /**
- * The timeout for mini clock updates.
- */
- private static final Duration miniClockUpdateTimeout = Duration.ofMillis(500);
-
- /**
- * The mini clock thread prefix.
- */
- private static final String minClockUpdaterThreadNamePrefix = "Mini CLock Updater";
-
- /**
- * The time formatter for getting the current time accounting for the gmt offset.
- */
- private static final SimpleDateFormat timeFormatter = TimeUtil.weatherFormat;
-
- /**
- * The GMT timezone string ID.
- */
- private static final String GMT = "GMT";
-
- /**
- * The thread name for the clock time updater.
- */
- private static final String CLOCK_UPDATER_THREAD_NAME = "Clock Time Updater";
-
- /**
- * The delay between clock updates.
- */
- private static final Duration CLOCK_UPDATER_TIMEOUT = Duration.ofMillis(250);
-
- /**
- * The builder for getting the theme color.
- */
- private static GetInputBuilder themeColorBuilder = null;
-
- /**
- * The GMT timezone object.
- */
- private static final TimeZone gmtTimezone = TimeZone.getTimeZone(GMT);
-
- @Widget(triggers = "clock", description = widgetDescription)
- public static void showGui() {
- CyderThreadRunner.submit(() -> {
- UiUtil.closeIfOpen(clockFrame);
-
- clockColor = CyderColors.getGuiThemeColor();
-
- shouldUpdateWidget.set(true);
- setShowSecondHand(UserDataManager.INSTANCE.shouldShowClockWidgetSecondHand());
- setPaintHourLabels(UserDataManager.INSTANCE.shouldPaintClockHourLabels());
-
- IpData data = IpDataManager.INSTANCE.getIpData();
- currentLocation = commaJoiner.join(data.getCity(), data.getRegion(), data.getCountry_name());
- currentGmtOffset = getGmtFromUserLocation();
-
- CyderFrame.Builder builder = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(CLOCK);
- clockFrame = new CyderFrame(builder) {
- @Override
- public void dispose() {
- shouldUpdateWidget.set(false);
- super.dispose();
- }
- };
-
- digitalTimeAndDateLabel = new CyderLabel(getCurrentTimeAccountingForOffset(currentGmtOffset));
- digitalTimeAndDateLabel.setFont(clockFont);
- digitalTimeAndDateLabel.setBounds(digitalTimeAndDateLabelXPadding,
- CyderDragLabel.DEFAULT_HEIGHT + digitalTimeAndDateLabelYPadding,
- FRAME_WIDTH - 2 * digitalTimeAndDateLabelXPadding, 40);
- clockFrame.getContentPane().add(digitalTimeAndDateLabel);
-
- clockLabel = new JLabel() {
- @Override
- public void paintComponent(Graphics g) {
- super.paintComponent(g);
- Graphics2D g2d = (Graphics2D) g;
-
- g2d.setStroke(new BasicStroke(6));
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g2d.setColor(clockColor);
- g2d.setFont(CyderFonts.DEFAULT_FONT);
-
- if (paintHourLabels) {
- paintHourLabels(g2d);
- } else {
- paintHourBoxes(g2d);
- }
-
- g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-
- drawHourHand(g2d);
- drawMinuteHand(g2d);
-
- if (showSecondHand) drawSecondHand(g2d);
-
- drawCenterDot(g2d);
- }
- };
- clockLabel.setBounds(clockLabelPadding, 100, clockLabelLength, clockLabelLength);
- clockLabel.setBorder(new LineBorder(CyderColors.navy, 5));
- clockFrame.getContentPane().add(clockLabel);
-
- startClockUpdater();
- installDragLabelButtons();
-
- clockFrame.finalizeAndShow();
- }, CLOCK_WIDGET_INITIALIZER_THREAD_NAME);
- }
-
- /**
- * Draws the hour hand on the clock.
- *
- * @param g2d the 2D graphics object
- */
- @ForReadability
- private static void drawHourHand(Graphics2D g2d) {
- int hour = Integer.parseInt(TimeUtil.getTime(hourDaterPattern)) % ((int) TimeUtil.hoursInDay / 2);
-
- float oneHourAngle = (float) (AngleUtil.THREE_SIXTY_DEGREES / romanNumerals.size());
- double hourTheta = hour * oneHourAngle + AngleUtil.TWO_SEVENTY_DEGREES;
- hourTheta = AngleUtil.normalizeAngle360(hourTheta) * Math.PI / AngleUtil.ONE_EIGHTY_DEGREES;
- int hourHandDrawToX = (int) Math.round(hourHandRadius * Math.cos(hourTheta));
- int hourHandDrawToY = (int) Math.round(hourHandRadius * Math.sin(hourTheta));
- g2d.drawLine(clockLabelCenter, clockLabelCenter,
- clockLabelCenter + hourHandDrawToX,
- clockLabelCenter + hourHandDrawToY);
- }
-
- /**
- * Draws the minute hand on the clock.
- *
- * @param g2d the 2D graphics object
- */
- @ForReadability
- private static void drawMinuteHand(Graphics2D g2d) {
- int minute = Integer.parseInt(TimeUtil.getTime(minuteDatePattern));
-
- double minuteTheta = (minute / TimeUtil.minutesInHour) * Math.PI * 2.0 + Math.PI * 1.5;
- int minuteHandDrawToX = (int) Math.round(minuteHandRadius * Math.cos(minuteTheta));
- int minuteHandDrawToY = (int) Math.round(minuteHandRadius * Math.sin(minuteTheta));
- g2d.drawLine(clockLabelCenter, clockLabelCenter,
- clockLabelCenter + minuteHandDrawToX,
- clockLabelCenter + minuteHandDrawToY);
- }
-
- /**
- * Draws the second hand on the clock.
- *
- * @param g2d the current 2D graphics object
- */
- @ForReadability
- private static void drawSecondHand(Graphics2D g2d) {
- int second = Integer.parseInt(TimeUtil.getTime(secondDatePattern));
-
- double secondTheta = (second / TimeUtil.secondsInMinute)
- * Math.PI * 2.0f + Math.PI * 1.5;
- int secondHandDrawToX = (int) Math.round(secondHandRadius * Math.cos(secondTheta));
- int secondHandDrawToY = (int) Math.round(secondHandRadius * Math.sin(secondTheta));
- g2d.drawLine(clockLabelCenter, clockLabelCenter,
- clockLabelCenter + secondHandDrawToX,
- clockLabelCenter + secondHandDrawToY);
- }
-
- /**
- * Draws the center dot on the clock.
- *
- * @param g2d the current 2D graphics object
- */
- @ForReadability
- private static void drawCenterDot(Graphics2D g2d) {
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g2d.setColor(CyderColors.navy);
- g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
- g2d.fillOval(clockLabelCenter - centerDotRadius / 2, clockLabelCenter - centerDotRadius / 2,
- centerDotRadius, centerDotRadius);
- }
-
- /**
- * Draws the hour boxes on the clock.
- *
- * @param g2d the current 2D graphics object
- */
- @ForReadability
- private static void paintHourBoxes(Graphics2D g2d) {
- double hourTheta = 0.0;
-
- for (int i = 0 ; i < romanNumerals.size() ; i++) {
- double currentRadians = hourTheta * Math.PI / AngleUtil.ONE_EIGHTY_DEGREES;
- double x = maxHandRadius * Math.cos(currentRadians);
- double y = maxHandRadius * Math.sin(currentRadians);
-
- int topLeftX = (int) (x - hourBoxLabelLength / 2 + clockLabelCenter);
- int topleftY = (int) (y - hourBoxLabelLength / 2 + clockLabelCenter) + numeralLabelTopLeftYAdditive;
-
- g2d.fillRect(topLeftX, topleftY, hourBoxLabelLength, hourBoxLabelLength);
-
- hourTheta += hourThetaInc;
- }
- }
-
- /**
- * Draws the hour labels on the clock.
- *
- * @param g2d the current 2D graphics object
- */
- @ForReadability
- private static void paintHourLabels(Graphics2D g2d) {
- double hourTheta = 0.0;
-
- for (int i = 0 ; i < romanNumerals.size() ; i++) {
- double radians = hourTheta * Math.PI / AngleUtil.ONE_EIGHTY_DEGREES;
- double x = maxHandRadius * Math.cos(radians);
- double y = maxHandRadius * Math.sin(radians);
-
- int topLeftX = (int) (x - hourBoxLabelLength / 2 + clockLabelCenter) + 10;
- int topleftY = (int) (y - hourBoxLabelLength / 2 + clockLabelCenter);
-
- String minText = romanNumerals.get(i);
- g2d.drawString(minText, topLeftX - hourBoxLabelLength / 2,
- topleftY + hourBoxLabelLength / 2);
-
- hourTheta += hourThetaInc;
- }
- }
-
- /**
- * Starts the updating thread for the clock.
- */
- private static void startClockUpdater() {
- CyderThreadRunner.submit(() -> {
- while (shouldUpdateWidget.get()) {
- ThreadUtil.sleep(CLOCK_UPDATER_TIMEOUT.toMillis());
- digitalTimeAndDateLabel.setText(getCurrentTimeAccountingForOffset(currentGmtOffset));
- clockLabel.repaint();
- }
- }, CLOCK_UPDATER_THREAD_NAME);
- }
-
- /**
- * Installs the drag label buttons for this widget.
- */
- private static void installDragLabelButtons() {
- DragLabelTextButton miniClockButton = new DragLabelTextButton.Builder(MINI)
- .setTooltip(TOOLTIP)
- .setClickAction(ClockWidget::spawnMiniClock)
- .build();
- clockFrame.getTopDragLabel().addRightButton(miniClockButton, 0);
-
- DragLabelTextButton colorButton = new DragLabelTextButton.Builder(COLOR)
- .setTooltip(THEME_COLOR)
- .setClickAction(getColorButtonClickRunnable())
- .build();
- clockFrame.getTopDragLabel().addRightButton(colorButton, 0);
-
- DragLabelTextButton locationButton = new DragLabelTextButton.Builder(LOCATION)
- .setTooltip(CURRENT_LOCATION)
- .setClickAction(getLocationButtonClickRunnable())
- .build();
- clockFrame.getTopDragLabel().addRightButton(locationButton, 0);
- }
-
- /**
- * Returns the runnable for the location drag label button.
- *
- * @return the runnable for the location drag label button
- */
- private static Runnable getLocationButtonClickRunnable() {
- return () -> CyderThreadRunner.submit(() -> {
- Optional optionalPossibleLocation = GetterUtil.getInstance().getInput(
- new GetInputBuilder(LOCATION, locationLabelText)
- .setInitialFieldText(currentLocation)
- .setSubmitButtonText(SET_LOCATION)
- .setRelativeTo(clockFrame)
- .setDisableRelativeTo(true));
- if (optionalPossibleLocation.isEmpty()) return;
- String possibleLocation = optionalPossibleLocation.get();
-
- Optional optionalWeatherData = WeatherUtil.getWeatherData(possibleLocation);
- if (optionalWeatherData.isEmpty()) {
- Console.INSTANCE.getConsoleCyderFrame().inform("Sorry, "
- + "but the Weather Key has not been set or is invalid"
- + ", as a result, many features of Cyder will not work as intended. "
- + "Please see the fields panel of the user editor to learn how to acquire "
- + "a key and set it.", "Weather Key Not Set");
- clockFrame.notify("Failed to update location");
- return;
- }
-
- WeatherData weatherData = optionalWeatherData.get();
- String timezoneString = String.valueOf(weatherData.getTimezone());
-
- int timezoneMinutes;
- try {
- timezoneMinutes = Integer.parseInt(timezoneString);
- } catch (Exception ignored) {
- clockFrame.notify("Failed to update location");
- return;
- }
- currentGmtOffset = timezoneMinutes / TimeUtil.secondsInHour;
- currentLocation = StringUtil.capsFirstWords(possibleLocation);
-
- Coord coord = weatherData.getCoord();
- String build = CyderStrings.openingBracket + coord.getLat() + CyderStrings.comma
- + coord.getLon() + CyderStrings.closingBracket;
-
- clockFrame.notify("Successfully updated location to " + weatherData.getName()
- + HtmlTags.breakTag + GMT + CyderStrings.colon + space
- + currentGmtOffset + HtmlTags.breakTag + build);
- }, "tester");
- }
-
- /**
- * Returns the runnable for the drag label color button.
- *
- * @return the runnable for the drag label color button
- */
- private static Runnable getColorButtonClickRunnable() {
- if (themeColorBuilder == null) {
- themeColorBuilder = new GetInputBuilder(THEME_COLOR, "Theme color")
- .setRelativeTo(clockFrame)
- .setFieldRegex(colorThemeFieldRegex)
- .setInitialFieldText(ColorUtil.toRgbHexString(clockColor));
- }
-
- return () -> CyderThreadRunner.submit(() -> {
- Optional optionalColor = GetterUtil.getInstance().getInput(themeColorBuilder);
- if (optionalColor.isEmpty()) return;
- String colorText = optionalColor.get().trim();
-
- Color newColor;
-
- try {
- newColor = ColorUtil.hexStringToColor(colorText);
- } catch (Exception ignored) {
- clockFrame.notify("Could not parse input for hex color: " + colorText);
- return;
- }
-
- setClockColor(newColor);
- }, CLOCK_COLOR_THEME_GETTER_WAITER);
- }
-
- /**
- * Sets the color of the clock to the provided color.
- *
- * @param clockColor the new clock color
- */
- @ForReadability
- private static void setClockColor(Color clockColor) {
- Preconditions.checkNotNull(clockColor);
-
- ClockWidget.clockColor = clockColor;
- clockLabel.repaint();
- }
-
- /**
- * Spawns a mini clock with its own timer based off of the current location.
- */
- private static void spawnMiniClock() {
- AtomicBoolean updateMiniClock = new AtomicBoolean(true);
-
- CyderFrame.Builder builder = new CyderFrame.Builder()
- .setWidth(miniFrameWidth)
- .setHeight(miniFrameHeight)
- .setTitle(TIMEZONE + space + openingParenthesis + GMT + currentGmtOffset + closingParenthesis);
- CyderFrame miniFrame = new CyderFrame(builder) {
- @Override
- public void dispose() {
- updateMiniClock.set(false);
- super.dispose();
- }
- };
- miniFrame.setTitlePosition(TitlePosition.CENTER);
-
- JLabel currentTimeLabel =
- new JLabel(getCurrentTimeAccountingForOffset(currentGmtOffset), SwingConstants.CENTER);
- currentTimeLabel.setForeground(CyderColors.navy);
- currentTimeLabel.setFont(CyderFonts.SEGOE_20);
- currentTimeLabel.setBounds(0, 50, miniFrameWidth, 30);
- miniFrame.getContentPane().add(currentTimeLabel);
-
- if (!currentLocation.isEmpty()) {
- String locationString = StringUtil.formatCommas(currentLocation);
- String labelText = locationString
- + space + openingParenthesis + GMT + currentGmtOffset + closingParenthesis;
- JLabel locationLabel = new JLabel(labelText, SwingConstants.CENTER);
- locationLabel.setForeground(CyderColors.navy);
- locationLabel.setFont(CyderFonts.SEGOE_20);
- locationLabel.setBounds(0, 80, miniFrameWidth, 30);
- miniFrame.getContentPane().add(locationLabel);
- }
-
- String threadName = minClockUpdaterThreadNamePrefix + space + CyderStrings.openingBracket
- + GMT + currentGmtOffset + CyderStrings.closingBracket;
- CyderThreadRunner.submit(() -> {
- // Localize since the global can change
- int localGmtOffset = currentGmtOffset;
- while (updateMiniClock.get()) {
- ThreadUtil.sleep(miniClockUpdateTimeout.toMillis());
- currentTimeLabel.setText(getCurrentTimeAccountingForOffset(localGmtOffset));
- }
- }, threadName);
-
- miniFrame.setVisible(true);
- miniFrame.setLocationRelativeTo(clockFrame);
- }
-
- /**
- * Returns the current time accounting for the GMT offset by adding
- * the number of hours to the returned time.
- *
- * @param gmtOffsetInHours the GMT offset for the location
- * @return the current time accounting for the GMT offset
- */
- private static String getCurrentTimeAccountingForOffset(int gmtOffsetInHours) {
- Calendar calendar = Calendar.getInstance();
-
- timeFormatter.setTimeZone(TimeZone.getTimeZone(GMT));
-
- try {
- calendar.add(Calendar.HOUR, gmtOffsetInHours);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- return timeFormatter.format(calendar.getTime());
- }
-
- /**
- * Possible gmt units used for hands of the clock.
- */
- private enum GmtUnit {
- HOUR("h"),
- MINUTE("m"),
- SECOND("s");
-
- private final String unitString;
- private final SimpleDateFormat dateFormatter;
-
- GmtUnit(String unitString) {
- this.unitString = unitString;
- this.dateFormatter = new SimpleDateFormat(unitString);
- }
-
- /**
- * Returns the unit string for this gmt unit.
- *
- * @return the unit string for this gmt unit
- */
- public String getUnitString() {
- return unitString;
- }
-
- /**
- * Returns the date formatter for this gmt unit.
- *
- * @return the date formatter for this gmt unit
- */
- public SimpleDateFormat getDateFormatter() {
- return dateFormatter;
- }
- }
-
- /**
- * Returns the h/m/s provided accounting for the GMT offset
- *
- * @param unit the gmt unit, that of hour, minute, or second
- * @return the unit accounting for the GMT offset
- */
- private static int getUnitForCurrentGmt(GmtUnit unit) {
- Calendar calendar = Calendar.getInstance();
- SimpleDateFormat dateFormatter = unit.getDateFormatter();
- dateFormatter.setTimeZone(gmtTimezone);
-
- try {
- calendar.add(Calendar.HOUR, currentGmtOffset);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- return Integer.parseInt(dateFormatter.format(calendar.getTime()));
- }
-
- /**
- * Returns the GMT based off of the current location.
- *
- * @return the GMT based off of the current location
- */
- private static int getGmtFromUserLocation() {
- String key = Props.weatherKey.getValue();
-
- if (key.isEmpty()) {
- Console.INSTANCE.getConsoleCyderFrame().inform("Sorry, "
- + "but the Weather Key has not been set or is invalid"
- + ", as a result, many features of Cyder will not work as intended. "
- + "Please see the fields panel of the user editor to learn how to acquire a key"
- + " and set it.", "Weather Key Not Set");
-
- resetGmtOffset();
- return 0;
- }
-
- Optional optionalWeatherData = WeatherUtil.getWeatherData(currentLocation);
- if (optionalWeatherData.isEmpty()) {
- resetGmtOffset();
- return 0;
- }
-
- WeatherData weatherData = optionalWeatherData.get();
- currentGmtOffset = Integer.parseInt(String.valueOf(weatherData.getTimezone())) / TimeUtil.secondsInHour;
- return currentGmtOffset;
- }
-
- /**
- * Resets the GMT offset to 0.
- */
- private static void resetGmtOffset() {
- currentGmtOffset = 0;
- currentLocation = DEFAULT_LOCATION;
- }
-
- /**
- * Sets whether to show the second hand.
- *
- * @param showSecondHand whether to show the second hand
- */
- @ForReadability
- public static void setShowSecondHand(boolean showSecondHand) {
- ClockWidget.showSecondHand = showSecondHand;
-
- if (clockLabel != null && shouldUpdateWidget.get()) {
- clockLabel.repaint();
- }
- }
-
- /**
- * Sets whether the hour labels should be painted.
- *
- * @param paintHourLabels whether the hour labels should be painted
- */
- @ForReadability
- public static void setPaintHourLabels(boolean paintHourLabels) {
- ClockWidget.paintHourLabels = paintHourLabels;
-
- if (clockLabel != null && shouldUpdateWidget.get()) {
- clockLabel.repaint();
- }
- }
-}
diff --git a/src/main/java/cyder/widgets/ColorConverterWidget.java b/src/main/java/cyder/widgets/ColorConverterWidget.java
deleted file mode 100644
index 74b32265c..000000000
--- a/src/main/java/cyder/widgets/ColorConverterWidget.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package cyder.widgets;
-
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.SuppressCyderInspections;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.constants.CyderRegexPatterns;
-import cyder.enumerations.CyderInspection;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.utils.ColorUtil;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-
-/**
- * A widget for converting between rgb and hex colors.
- */
-@Vanilla
-@CyderAuthor
-public class ColorConverterWidget {
- /**
- * Returns a new instance of ColorConverterWidget.
- *
- * @return a new instance of ColorConverterWidget
- */
- public static ColorConverterWidget getInstance() {
- return new ColorConverterWidget();
- }
-
- /**
- * Creates a new Color Converter Widget.
- */
- private ColorConverterWidget() {
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * The widget description.
- */
- private static final String description = "A color converter widget to convert from rgb to hex and vice versa";
-
- /**
- * A widget for converting between rgb and hex colors.
- */
- @SuppressCyderInspections(CyderInspection.WidgetInspection)
- @Widget(triggers = {"color converter", "color"}, description = description)
- public static void showGui() {
- getInstance().innerShowGui();
- }
-
- /**
- * Shows the gui of this widget.
- */
- public void innerShowGui() {
- innerShowGui(CyderFrame.getDominantFrame());
- }
-
- /**
- * The width of the frame.
- */
- private static final int FRAME_WIDTH = 300;
-
- /**
- * The height of the frame.
- */
- private static final int FRAME_HEIGHT = 400;
-
- /**
- * The color preview text.
- */
- private static final String COLOR_PREVIEW = "Color preview";
-
- /**
- * The hex value text.
- */
- private static final String HEX_VALUE = "Hex value";
-
- /**
- * The rgb value text.
- */
- private static final String RGB_VALUE = "Rgb value";
-
- /**
- * The color converter text.
- */
- private static final String TITLE = "Color Converter";
-
- /**
- * The limit of characters for the rgb field.
- */
- private static final int RGB_FIELD_LIMIT = 11;
-
- /**
- * The border for the color preview block.
- */
- private static final LineBorder COLOR_BLOCK_BORDER = new LineBorder(CyderColors.navy, 5);
-
- /**
- * The font for the rgb and hex fields.
- */
- private static final Font fieldFont = new Font(CyderFonts.SEGOE_UI_BLACK, Font.BOLD, 26);
-
- /**
- * The limit of characters for the hex field.
- */
- private static final int hexFieldLimit = 6;
-
- /**
- * The string formatter for the hex field.
- */
- private static final String hexFieldStringFormatter = "#%02X%02X%02X";
-
- /**
- * The partition size for the spacers.
- */
- private static final int spacerPartitionLength = 10;
-
- /**
- * The partition space for the color labels and color block.
- */
- private static final int colorLabelAndBlockPartitionLength = 15;
-
- /**
- * The partition space for the text fields.
- */
- private static final int fieldPartitionLength = 10;
-
- /**
- * The size of the text fields and color block.
- */
- private static final Dimension fieldAndBlockSize = new Dimension(220, 50);
-
- /**
- * The starting color for the fields.
- */
- private static final Color startingColor = CyderColors.navy;
-
- /**
- * The height of labels.
- */
- private static final int labelHeight = 30;
-
- /**
- * Shows the gui of this widget.
- *
- * @param relativeTo the component to set the widget relative to
- */
- public void innerShowGui(Component relativeTo) {
- CyderFrame colorFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .build();
- colorFrame.setTitle(TITLE);
-
- colorFrame.initializeResizing();
- colorFrame.setResizable(true);
- colorFrame.setBackgroundResizing(true);
- colorFrame.setMinimumSize(new Dimension(FRAME_WIDTH, FRAME_HEIGHT));
- colorFrame.setMaximumSize(new Dimension(FRAME_WIDTH, 2 * FRAME_HEIGHT));
-
- CyderPartitionedLayout layout = new CyderPartitionedLayout();
-
- JLabel colorLabel = new JLabel(COLOR_PREVIEW);
- colorLabel.setHorizontalAlignment(JLabel.CENTER);
- colorLabel.setFont(CyderFonts.SEGOE_20);
- colorLabel.setForeground(CyderColors.navy);
- colorLabel.setSize(FRAME_WIDTH, labelHeight);
-
- JLabel hexLabel = new JLabel(HEX_VALUE);
- hexLabel.setHorizontalAlignment(JLabel.CENTER);
- hexLabel.setFont(CyderFonts.SEGOE_20);
- hexLabel.setForeground(CyderColors.navy);
- hexLabel.setSize(FRAME_WIDTH, labelHeight);
-
- JLabel rgbLabel = new JLabel(RGB_VALUE);
- rgbLabel.setHorizontalAlignment(JLabel.CENTER);
- rgbLabel.setFont(CyderFonts.SEGOE_20);
- rgbLabel.setForeground(CyderColors.navy);
- rgbLabel.setSize(FRAME_WIDTH, labelHeight);
-
- JTextField colorBlock = new JTextField();
- colorBlock.setBackground(CyderColors.navy);
- colorBlock.setFocusable(false);
- colorBlock.setCursor(null);
- colorBlock.setToolTipText(COLOR_PREVIEW);
- colorBlock.setBorder(COLOR_BLOCK_BORDER);
- colorBlock.setSize(fieldAndBlockSize);
-
- CyderTextField rgbField = new CyderTextField(RGB_FIELD_LIMIT);
- rgbField.setHorizontalAlignment(JTextField.CENTER);
- rgbField.setText(startingColor.getRed() + CyderStrings.comma + startingColor.getGreen()
- + CyderStrings.comma + startingColor.getBlue());
-
- CyderTextField hexField = new CyderTextField(hexFieldLimit);
- hexField.setKeyEventRegexMatcher(CyderRegexPatterns.hexPattern.pattern());
- hexField.setHorizontalAlignment(JTextField.CENTER);
- hexField.setText(String.format(hexFieldStringFormatter, startingColor.getRed(),
- startingColor.getGreen(), startingColor.getBlue())
- .replace(CyderStrings.hash, ""));
- hexField.setBackground(CyderColors.empty);
- hexField.setToolTipText(HEX_VALUE);
- hexField.setFont(fieldFont);
- hexField.addKeyListener(new KeyAdapter() {
- public void keyReleased(KeyEvent e) {
- try {
- Color hexFieldColor = ColorUtil.hexStringToColor(hexField.getText());
- rgbField.setText(hexFieldColor.getRed() + CyderStrings.comma + hexFieldColor.getGreen()
- + CyderStrings.comma + hexFieldColor.getBlue());
- colorBlock.setBackground(hexFieldColor);
- } catch (Exception ignored) {}
- }
- });
- hexField.setSize(fieldAndBlockSize);
- hexField.setOpaque(false);
-
- rgbField.setBackground(CyderColors.empty);
- rgbField.setKeyEventRegexMatcher(CyderRegexPatterns.rgbPattern.pattern());
- rgbField.setToolTipText(RGB_VALUE);
- rgbField.setFont(fieldFont);
- rgbField.addKeyListener(new KeyAdapter() {
- public void keyReleased(KeyEvent e) {
- try {
- String text = rgbField.getText();
- if (!text.contains(CyderStrings.comma)) return;
-
- String[] parts = text.split(CyderStrings.comma);
- if (parts.length != 3) return;
-
- int r = Integer.parseInt(parts[0]);
- int g = Integer.parseInt(parts[1]);
- int b = Integer.parseInt(parts[2]);
-
- Color color = new Color(r, g, b);
- hexField.setText(ColorUtil.toRgbHexString(color));
- colorBlock.setBackground(color);
- } catch (Exception ignored) {}
- }
- });
- rgbField.setSize(fieldAndBlockSize);
- rgbField.setOpaque(false);
-
- layout.spacer(spacerPartitionLength);
- layout.addComponent(hexLabel, colorLabelAndBlockPartitionLength);
- layout.addComponent(hexField, fieldPartitionLength);
- layout.addComponent(rgbLabel, colorLabelAndBlockPartitionLength);
- layout.addComponent(rgbField, fieldPartitionLength);
- layout.addComponent(colorLabel, colorLabelAndBlockPartitionLength);
- layout.addComponent(colorBlock, colorLabelAndBlockPartitionLength);
- layout.spacer(spacerPartitionLength);
-
- colorFrame.setCyderLayout(layout);
-
- rgbField.addFocusListener(new FocusAdapter() {
- @Override
- public void focusLost(FocusEvent e) {
- hexField.requestFocus();
- }
- });
- hexField.addFocusListener(new FocusAdapter() {
- @Override
- public void focusLost(FocusEvent e) {
- rgbField.requestFocus();
- }
- });
-
- colorFrame.finalizeAndShow(relativeTo);
- }
-}
diff --git a/src/main/java/cyder/widgets/ConvexHullWidget.java b/src/main/java/cyder/widgets/ConvexHullWidget.java
deleted file mode 100644
index c4c900013..000000000
--- a/src/main/java/cyder/widgets/ConvexHullWidget.java
+++ /dev/null
@@ -1,430 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.*;
-import cyder.constants.CyderColors;
-import cyder.enumerations.CyderInspection;
-import cyder.exceptions.IllegalMethodException;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.strings.CyderStrings;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.grid.CyderGrid;
-import cyder.ui.grid.GridNode;
-import cyder.ui.pane.CyderPanel;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-
-/**
- * Convex hull widget that solve a convex hull problem using a CyderGrid as the drawing label.
- */
-@Vanilla
-@CyderAuthor
-public final class ConvexHullWidget {
- /**
- * The CyderFrame to use for the convex hull widget.
- */
- private static CyderFrame hullFrame;
-
- /**
- * The grid to use to represent points in space.
- */
- private static CyderGrid gridComponent;
-
- /**
- * Suppress default constructor.
- */
- private ConvexHullWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The title of the frame.
- */
- private static final String FRAME_TITLE = "Convex Hull";
-
- /**
- * The solve button text.
- */
- private static final String SOLVE = "Solve";
-
- /**
- * The reset button text.
- */
- private static final String RESET = "Reset";
-
- /**
- * The number of grid nodes.
- */
- private static final int GRID_NODES = 175;
-
- /**
- * The length of the grid.
- */
- private static final int GRID_LENGTH = 700;
-
- /**
- * The padding around the edges of the grid.
- */
- private static final int GRID_PADDING = 3;
-
- /**
- * The size of the parent component for the grid.
- */
- private static final int GRID_PARENT_LEN = GRID_LENGTH + 2 * GRID_PADDING;
-
- /**
- * The width of the frame.
- */
- private static final int FRAME_WIDTH = 800;
-
- /**
- * The height of the frame.
- */
- private static final int FRAME_HEIGHT = 850;
-
- /**
- * The size of the buttons.
- */
- private static final Dimension BUTTON_SIZE = new Dimension(300, 40);
-
- /**
- * The top and bottom button padding.
- */
- private static final int BUTTON_Y_PADDING = 10;
-
- /**
- * The color of the nodes the user places on the grid.
- */
- private static final Color PLACED_NODE_COLOR = CyderColors.regularPink;
-
- /**
- * The color of the nodes placed by the algorithm.
- */
- private static final Color WALL_NODE_COLOR = CyderColors.navy;
-
- /**
- * The border for the grid component.
- */
- private static final LineBorder GRID_PARENT_BORDER = new LineBorder(CyderColors.navy, GRID_PADDING);
-
- /**
- * The minimum number of points required to form a polygon in 2D space.
- */
- private static final int MIN_POLYGON_POINTS = 3;
-
- /**
- * The text to display in a notification if the four corners of the grid are occupied.
- */
- private static final String FOUR_CORNERS = "Congratulations, you played yourself";
-
- /**
- * Shows the convex hull widget.
- */
- @SuppressCyderInspections(CyderInspection.WidgetInspection)
- @Widget(triggers = {"convex", "convex hull"}, description = "A convex hull algorithm visualizer")
- public static void showGui() {
- UiUtil.closeIfOpen(hullFrame);
-
- hullFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(FRAME_TITLE)
- .build();
-
- JLabel gridComponentParent = new JLabel();
- gridComponentParent.setSize(GRID_PARENT_LEN, GRID_PARENT_LEN);
- gridComponentParent.setBorder(GRID_PARENT_BORDER);
-
- gridComponent = new CyderGrid(GRID_NODES, GRID_LENGTH);
- gridComponent.setDrawGridLines(false);
- gridComponent.setBounds(GRID_PADDING, GRID_PADDING, GRID_LENGTH, GRID_LENGTH);
- gridComponent.setResizable(false);
- gridComponent.setNodeColor(PLACED_NODE_COLOR);
- gridComponent.setBackground(CyderColors.vanilla);
- gridComponent.installClickListener();
- gridComponent.installDragListener();
- gridComponent.setSaveStates(false);
- gridComponentParent.add(gridComponent);
-
- CyderPartitionedLayout buttonPartitionedLayout = new CyderPartitionedLayout();
- buttonPartitionedLayout.setPartitionDirection(CyderPartitionedLayout.PartitionDirection.ROW);
-
- buttonPartitionedLayout.spacer(10);
- CyderButton solveButton = new CyderButton(SOLVE);
- solveButton.setSize(BUTTON_SIZE);
- solveButton.addActionListener(e -> solveButtonAction());
- buttonPartitionedLayout.addComponent(solveButton, 40);
-
- CyderButton resetButton = new CyderButton(RESET);
- resetButton.addActionListener(e -> reset());
- resetButton.setSize(BUTTON_SIZE);
- buttonPartitionedLayout.addComponent(resetButton, 40);
- buttonPartitionedLayout.spacer(10);
-
- CyderPartitionedLayout partitionedLayout = new CyderPartitionedLayout();
- partitionedLayout.spacer(10);
-
- partitionedLayout.addComponent(gridComponentParent, 70);
-
- partitionedLayout.spacer(10);
-
- CyderPanel buttonPanel = new CyderPanel(buttonPartitionedLayout);
- buttonPanel.setSize(FRAME_WIDTH, (int) (BUTTON_SIZE.getHeight() + 2 * BUTTON_Y_PADDING));
- partitionedLayout.addComponent(buttonPanel, 10);
-
- hullFrame.setCyderLayout(partitionedLayout);
- hullFrame.finalizeAndShow();
- }
-
- /**
- * The actions to invoke when the solve button is pressed.
- */
- private static void solveButtonAction() {
- gridComponent.setGridNodes(new ArrayList<>(gridComponent.getNodesOfColor(PLACED_NODE_COLOR)));
-
- if (gridComponent.getNodeCount() < MIN_POLYGON_POINTS) {
- hullFrame.notify(MIN_POLYGON_POINTS + " points are required to create a polygon in 2D space");
- return;
- }
-
- ArrayList points = new ArrayList<>();
- gridComponent.getGridNodes().forEach(node -> points.add(new Point(node.getX(), node.getY())));
-
- ImmutableList hull = solveGrahamScan(points);
- connectHullPointsWithLines(hull);
- checkFourCorners();
- gridComponent.repaint();
- }
-
- /**
- * Connects all points contained within the provided list with lines on the grid.
- *
- * @param hullPoints the points of the convex hull to connect with lines
- */
- private static void connectHullPointsWithLines(ImmutableList hullPoints) {
- Preconditions.checkNotNull(hullPoints);
- Preconditions.checkArgument(hullPoints.size() >= MIN_POLYGON_POINTS);
-
- for (int i = 0 ; i < hullPoints.size() ; i++) {
- Point firstPoint = hullPoints.get(i);
- int secondPointIndex = (i == hullPoints.size() - 1) ? 0 : i + 1;
- Point secondPoint = hullPoints.get(secondPointIndex);
-
- addMidPointsToGrid(firstPoint, secondPoint);
- }
- }
-
- /**
- * Checks to see if the four corner grid nodes have a user-placed node in them.
- */
- @ForReadability
- private static void checkFourCorners() {
- int min = 0;
- int max = gridComponent.getNodeDimensionLength() - 1;
- ImmutableList cornerNodes = ImmutableList.of(
- /* Color is irrelevant here */
- new GridNode(WALL_NODE_COLOR, min, min),
- new GridNode(WALL_NODE_COLOR, min, max),
- new GridNode(WALL_NODE_COLOR, max, min),
- new GridNode(WALL_NODE_COLOR, max, max)
- );
-
- if (gridComponent.getGridNodes().containsAll(cornerNodes)) {
- hullFrame.notify(FOUR_CORNERS);
- }
- }
-
- /**
- * Recursively finds the middle point between the provided points and adds
- * it to the grid meaning a line between the original two provided points
- * is created on the grid.
- *
- * @param firstPoint the first point
- * @param secondPoint the second point
- */
- private static void addMidPointsToGrid(Point firstPoint, Point secondPoint) {
- Preconditions.checkNotNull(firstPoint);
- Preconditions.checkNotNull(secondPoint);
-
- if (firstPoint.equals(secondPoint)) return;
-
- int midXPoints = (int) (secondPoint.getX() + firstPoint.getX()) / 2;
- int midYPoints = (int) (secondPoint.getY() + firstPoint.getY()) / 2;
- Point midPoint = new Point(midXPoints, midYPoints);
-
- if (midPoint.equals(firstPoint) || midPoint.equals(secondPoint)) return;
-
- GridNode gridMidPoint = new GridNode(WALL_NODE_COLOR, midXPoints, midYPoints);
- if (gridComponent.contains(gridMidPoint)) {
- gridComponent.removeNode(gridMidPoint);
- }
- gridComponent.addNode(gridMidPoint);
-
- addMidPointsToGrid(firstPoint, midPoint);
- addMidPointsToGrid(midPoint, secondPoint);
- }
-
- /**
- * Solves the convex hull problem given the list of points.
- *
- * @param points the list of points
- * @return the points in the convex hull
- */
- private static ImmutableList solveGrahamScan(ArrayList points) {
- Deque stack = new ArrayDeque<>();
-
- Point bottomLeftMostPoint = getBottomLeftMostPoint(points);
- sortPointsByAngle(points, bottomLeftMostPoint);
-
- int pointIndex = 0;
- stack.push(points.get(pointIndex++));
- stack.push(points.get(pointIndex++));
-
- for (int i = pointIndex, size = points.size() ; i < size ; i++) {
- Point next = points.get(i);
- Point poppedPoint = stack.pop();
-
- while (stack.peek() != null) {
- PointRotation rotation = determineRotation(stack.peek(), poppedPoint, next);
- if (rotation == PointRotation.COUNTER_CLOCK_WISE) break;
- poppedPoint = stack.pop();
- }
-
- stack.push(poppedPoint);
- stack.push(points.get(i));
- }
-
- Point poppedPoint = stack.pop();
- if (stack.peek() == null) {
- return ImmutableList.of();
- }
-
- PointRotation rotation = determineRotation(stack.peek(), poppedPoint, bottomLeftMostPoint);
- if (rotation == PointRotation.COUNTER_CLOCK_WISE) {
- stack.push(poppedPoint);
- }
-
- return ImmutableList.copyOf(stack);
- }
-
- /**
- * Returns the node with the minimum y value from the provided list.
- * If two points contain the same y value, the point with the minimum x value is returned.
- *
- * @param points the list of points
- * @return the bottom left most point
- */
- private static Point getBottomLeftMostPoint(ArrayList points) {
- Preconditions.checkNotNull(points);
- Preconditions.checkArgument(!points.isEmpty());
-
- Point min = points.get(0);
- for (Point point : points) {
- if (point.getY() <= min.getY()) {
- if (point.getY() < min.getY()) {
- min = point;
- }
- // Choose leftmost point if same y value
- else if (point.getX() < min.getX()) {
- min = point;
- }
- }
- }
-
- return min;
- }
-
- /**
- * The possible degrees of rotate between two points and a reference point.
- */
- private enum PointRotation {
- /**
- * The points result in a clock wise turn.
- */
- CLOCK_WISE,
- /**
- * The points result in a counter clock wise turn.
- */
- COUNTER_CLOCK_WISE,
- /**
- * The points are co-linear.
- */
- CO_LINEAR
- }
-
- /**
- * Determines the rotation between the first point and second point relative to the reference point.
- *
- * @param firstPoint the first point
- * @param secondPoint the second point
- * @param referencePoint the reference point
- * @return the rotation between the first point and second point relative to the reference point
- */
- private static PointRotation determineRotation(Point firstPoint, Point secondPoint, Point referencePoint) {
- Preconditions.checkNotNull(firstPoint);
- Preconditions.checkNotNull(secondPoint);
- Preconditions.checkNotNull(referencePoint);
-
- float area = (secondPoint.x - firstPoint.x) * (referencePoint.y - firstPoint.y)
- - (secondPoint.y - firstPoint.y) * (referencePoint.x - firstPoint.x);
-
- if (area < 0) {
- return PointRotation.CLOCK_WISE;
- } else if (area > 0) {
- return PointRotation.COUNTER_CLOCK_WISE;
- } else {
- return PointRotation.CO_LINEAR;
- }
- }
-
- /**
- * Sorts the list of points by angle using the reference point.
- *
- * @param points the list of points
- * @param referencePoint the reference point
- */
- private static void sortPointsByAngle(ArrayList points, Point referencePoint) {
- Preconditions.checkNotNull(points);
- Preconditions.checkNotNull(referencePoint);
-
- points.sort((firstPoint, secondPoint) -> {
- if (firstPoint == referencePoint) {
- return -1;
- } else if (secondPoint == referencePoint) {
- return 1;
- } else if (firstPoint == secondPoint) {
- return 0;
- }
-
- PointRotation rotation = determineRotation(referencePoint, firstPoint, secondPoint);
- if (rotation == PointRotation.CO_LINEAR) {
- if (Double.compare(firstPoint.getX(), secondPoint.getX()) == 0) {
- return firstPoint.getY() < secondPoint.getY() ? -1 : 1;
- } else {
- return firstPoint.getX() < secondPoint.getX() ? -1 : 1;
- }
- } else if (rotation == PointRotation.CLOCK_WISE) {
- return 1;
- } else if (rotation == PointRotation.COUNTER_CLOCK_WISE) {
- return -1;
- }
-
- throw new IllegalStateException("Invalid rotation: " + rotation);
- });
- }
-
- /**
- * Resets the convex hull state and grid.
- */
- private static void reset() {
- gridComponent.clearGrid();
- }
-}
diff --git a/src/main/java/cyder/widgets/ExampleWidget.java b/src/main/java/cyder/widgets/ExampleWidget.java
deleted file mode 100644
index e5f99b834..000000000
--- a/src/main/java/cyder/widgets/ExampleWidget.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cyder.widgets;
-
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.SuppressCyderInspections;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.enumerations.CyderInspection;
-import cyder.layouts.CyderGridLayout;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.ui.button.CyderButton;
-import cyder.ui.frame.CyderFrame;
-import cyder.user.UserDataManager;
-
-/**
- * An example widget for new Cyder developers to learn the standard widget construction.
- */
-@Vanilla
-@CyderAuthor
-public final class ExampleWidget {
- /**
- * Suppress default constructor from access outside of this class and log
- * when objects are created by the static factory method.
- */
- private ExampleWidget() {
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * Returns an instance of ExampleWidget.
- *
- * @return an instance of ExampleWidget
- */
- public static ExampleWidget getInstance() {
- return new ExampleWidget();
- }
-
- @SuppressCyderInspections(CyderInspection.WidgetInspection)
- @Widget(triggers = "example widget", description = "An example base widget for new Cyder developers")
- public static void showGui() {
- getInstance().innerShowGui();
- }
-
- /**
- * Shows the widget.
- */
- private void innerShowGui() {
- CyderFrame cyderFrame = new CyderFrame.Builder()
- .setWidth(600)
- .setHeight(600)
- .setTitle("Example Widget")
- .build();
-
- CyderButton cyderButton = new CyderButton("Button");
- cyderButton.setSize(200, 40);
- cyderButton.addActionListener(e -> {
- // Your logic here or a method reference to a local method (See EJ items 42 and 43)
- cyderFrame.notify("Hello " + UserDataManager.INSTANCE.getUsername() + "!");
- });
-
- CyderGridLayout gridLayout = new CyderGridLayout(1, 1);
- gridLayout.addComponent(cyderButton);
-
- cyderFrame.setCyderLayout(gridLayout);
-
- cyderFrame.finalizeAndShow();
- }
-}
diff --git a/src/main/java/cyder/widgets/FileSignatureWidget.java b/src/main/java/cyder/widgets/FileSignatureWidget.java
deleted file mode 100644
index cfc953445..000000000
--- a/src/main/java/cyder/widgets/FileSignatureWidget.java
+++ /dev/null
@@ -1,324 +0,0 @@
-package cyder.widgets;
-
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.constants.CyderIcons;
-import cyder.constants.CyderRegexPatterns;
-import cyder.exceptions.IllegalMethodException;
-import cyder.getter.GetFileBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.network.NetworkUtil;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.label.CyderLabel;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.Optional;
-
-@Vanilla
-@CyderAuthor
-public final class FileSignatureWidget {
- /**
- * The file to validate.
- */
- private static File currentFile;
-
- /**
- * The widget frame.
- */
- private static CyderFrame signatureFrame;
-
- /**
- * The expected byte signature input field.
- */
- private static CyderTextField signatureField;
-
- /**
- * The label to which the results are displayed on.
- */
- private static CyderLabel resultLabel;
-
- /**
- * The label for the files signatures sheet.
- */
- private static CyderLabel fileSignaturesSheetLabel;
-
- /**
- * The get file button.
- */
- private static CyderButton getFile;
-
- /**
- * The check file button.
- */
- private static CyderButton checkFile;
-
- private static final String FILE_SIGNATURE_FILE_CHOOSER = "File Signature File Chooser";
-
- /**
- * A link for common file signatures.
- */
- public static final String WIKIPEDIA_FILE_SIGNATURES = "https://en.wikipedia.org/wiki/List_of_file_signatures";
-
- /**
- * The mouse listener for the files signature sheet.
- */
- private static final MouseListener fileSignaturesSheetLabelMouseListener = new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- NetworkUtil.openUrl(WIKIPEDIA_FILE_SIGNATURES);
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- fileSignaturesSheetLabel.setForeground(CyderColors.regularRed);
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- fileSignaturesSheetLabel.setForeground(CyderColors.navy);
- }
- };
-
- /**
- * The widget description.
- */
- private static final String description = "A widget to read the raw file"
- + " hex data and determine if the file signature matches the provided signature";
-
- /**
- * The widget title.
- */
- private static final String TITLE = "File Signature Checker";
-
- /**
- * The font for the files signature sheet label.
- */
- private static final Font FILE_SIGNATURES_SHEET_LABEL_FONT = new Font(CyderFonts.AGENCY_FB, Font.BOLD, 28);
-
- /**
- * The select file text.
- */
- private static final String SELECT_FILE = "Select File";
-
- /**
- * The validate file type text.
- */
- private static final String VALIDATE_FILE_TYPE = "Validate File Type";
-
- /**
- * The comparison not yet performed text.
- */
- private static final String COMPARISON_NOT_YET_PERFORMED = "Comparison not performed yet";
-
- /**
- * The file signature sheet label text.
- */
- private static final String FILE_SIGNATURE_SHEET = "File Signature Sheet";
-
- /**
- * The choose file button text.
- */
- private static final String CHOOSE_FILE_TO_VALIDATE = "Choose file to validate";
-
- /**
- * The default label text if a file is not chosen.
- */
- private static final String PLEASE_CHOOSE_A_FILE = "Please choose a file";
-
- /**
- * The label text if a file signature is not entered.
- */
- private static final String PLEASE_ENTER_A_FILE_SIGNATURE = "Please enter a file signature";
-
- /**
- * The width of the frame.
- */
- private static final int FRAME_WIDTH = 400;
-
- /**
- * The height of the frame.
- */
- private static final int FRAME_HEIGHT = 420;
-
- /**
- * The text for the validate button if the validation is valid.
- */
- private static final String VALID = "Valid";
-
- /**
- * The text for the validate button if the validation is invalid.
- */
- private static final String INVALID = "Invalid";
-
- /**
- * The valid file label text.
- */
- private static final String validFileSignatureText = "File signature matches provided signature";
-
- /**
- * The invalid file label text.
- */
- private static final String invalidFileSignatureText = "File signature does NOT match provided signature; "
- + "If no more possible signature exist for this file, then it might be "
- + "unsafe/corrupted";
-
- /**
- * The tooltip for the validate button.
- */
- private static final String VALIDATE = "Validate";
-
- /**
- * The tooltip for the choose file button.
- */
- private static final String CHOOSE_FILE = "Choose file";
-
- /**
- * Suppress default constructor.
- */
- private FileSignatureWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Widget(triggers = {"file signature", "signature"}, description = description)
- public static void showGui() {
- signatureFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setBackgroundIcon(CyderIcons.defaultBackground)
- .build();
- signatureFrame.setTitle(TITLE);
-
- signatureField = new CyderTextField();
- signatureField.setHorizontalAlignment(JTextField.CENTER);
- signatureField.setBounds(50, 120, 300, 40);
- signatureField.setToolTipText("Enter the hex file signature of the file type you presume this file to be");
- signatureField.addActionListener(e -> validate());
- signatureFrame.getContentPane().add(signatureField);
-
- fileSignaturesSheetLabel = new CyderLabel(FILE_SIGNATURE_SHEET);
- fileSignaturesSheetLabel.setBounds(50, 50, 300, 40);
- fileSignaturesSheetLabel.setFont(FILE_SIGNATURES_SHEET_LABEL_FONT);
- fileSignaturesSheetLabel.setToolTipText("Click here to view a list of common file signatures");
- fileSignaturesSheetLabel.addMouseListener(fileSignaturesSheetLabelMouseListener);
- signatureFrame.getContentPane().add(fileSignaturesSheetLabel);
-
- getFile = new CyderButton(SELECT_FILE);
- getFile.setBackground(CyderColors.regularPink);
- getFile.setBounds(50, 190, 300, 40);
- getFile.addActionListener(e -> getFileAction());
- getFile.setToolTipText(CHOOSE_FILE);
- signatureFrame.getContentPane().add(getFile);
-
- checkFile = new CyderButton(VALIDATE_FILE_TYPE);
- checkFile.setBackground(CyderColors.regularBlue);
- checkFile.setBounds(50, 260, 300, 40);
- checkFile.addActionListener(e -> validate());
- checkFile.setToolTipText(VALIDATE);
- signatureFrame.getContentPane().add(checkFile);
-
- resultLabel = new CyderLabel(COMPARISON_NOT_YET_PERFORMED);
- resultLabel.setBounds(50, 300, 300, 120);
- signatureFrame.getContentPane().add(resultLabel);
-
- signatureFrame.finalizeAndShow();
- }
-
- /**
- * The action to perform when the choose file button is clicked.
- */
- private static void getFileAction() {
- try {
- CyderThreadRunner.submit(() -> {
- try {
- Optional optionalFile = GetterUtil.getInstance().getFile(
- new GetFileBuilder(CHOOSE_FILE_TO_VALIDATE).setRelativeTo(signatureFrame));
- if (optionalFile.isEmpty()) return;
- currentFile = optionalFile.get();
- resetResults();
- } catch (Exception ex) {
- ExceptionHandler.handle(ex);
- }
- }, FILE_SIGNATURE_FILE_CHOOSER);
- } catch (Exception ex) {
- ExceptionHandler.handle(ex);
- }
- }
-
- /**
- * Resets any results from a file validation including:
- *
- * Setting the text of the get file button to the current file's name
- * Setting the text of the check file button
- * Resetting the results label text
- *
- */
- private static void resetResults() {
- getFile.setText(currentFile.getName());
- checkFile.setText(VALIDATE_FILE_TYPE);
- resultLabel.setText(COMPARISON_NOT_YET_PERFORMED);
- }
-
- /**
- * Attempts to validate the chosen file if present with the provided file signature if present.
- */
- private static void validate() {
- if (currentFile == null) {
- signatureFrame.notify(PLEASE_CHOOSE_A_FILE);
- return;
- } else if (signatureField.getTrimmedText().isEmpty()) {
- signatureFrame.notify(PLEASE_ENTER_A_FILE_SIGNATURE);
- return;
- }
-
- // Remove any byte identifiers and whitespace
- // Text such as "0xFF 0xA0" becomes "FFA0"
- String expectedByteSignature = signatureField.getTrimmedText()
- .replaceAll("0x", "")
- .replaceAll(CyderRegexPatterns.whiteSpaceRegex, "");
-
- StringBuilder stringBuilder = new StringBuilder();
-
- try {
- InputStream inputStream = new FileInputStream(currentFile);
- int columns = (int) Math.ceil(expectedByteSignature.length() / 2.0);
-
- long streamPointer = 0;
- while (inputStream.available() > 0) {
- long col = streamPointer++ % columns;
- stringBuilder.append(String.format("%02x ", inputStream.read()));
-
- if (col == (columns - 1)) break;
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- String byteSignatureString = stringBuilder.toString()
- .replaceAll(CyderRegexPatterns.whiteSpaceRegex, "");
-
- if (expectedByteSignature.equalsIgnoreCase(byteSignatureString)) {
- resultLabel.setText(validFileSignatureText);
- checkFile.setText(VALID);
- } else {
- resultLabel.setText(invalidFileSignatureText);
- checkFile.setText(INVALID);
- }
-
- signatureField.flashField();
- }
-}
diff --git a/src/main/java/cyder/widgets/GameOfLifeWidget.java b/src/main/java/cyder/widgets/GameOfLifeWidget.java
deleted file mode 100644
index de8a22318..000000000
--- a/src/main/java/cyder/widgets/GameOfLifeWidget.java
+++ /dev/null
@@ -1,909 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.base.Preconditions;
-import com.google.errorprone.annotations.Immutable;
-import cyder.annotations.*;
-import cyder.constants.CyderColors;
-import cyder.enumerations.CyderInspection;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.getter.GetFileBuilder;
-import cyder.getter.GetInputBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.layouts.CyderGridLayout;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.time.TimeUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.grid.CyderGrid;
-import cyder.ui.grid.GridNode;
-import cyder.ui.label.CyderLabel;
-import cyder.ui.pane.CyderPanel;
-import cyder.ui.selection.CyderComboBox;
-import cyder.ui.selection.CyderComboBoxState;
-import cyder.ui.selection.CyderSwitch;
-import cyder.ui.selection.CyderSwitchState;
-import cyder.ui.slider.CyderSliderUi;
-import cyder.ui.slider.ThumbShape;
-import cyder.user.UserUtil;
-import cyder.utils.ArrayUtil;
-import cyder.utils.SerializationUtil;
-import cyder.utils.StaticUtil;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Optional;
-
-/**
- * Conway's game of life visualizer.
- */
-@Vanilla
-@CyderAuthor
-public final class GameOfLifeWidget {
- /**
- * Suppress default constructor.
- */
- private GameOfLifeWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The game of life frame.
- */
- private static CyderFrame conwayFrame;
-
- /**
- * The top-level grid used to display the current generation.
- */
- private static CyderGrid conwayGrid;
-
- /**
- * The button to begin/stop (pause) the simulation.
- */
- private static CyderButton stopSimulationButton;
-
- /**
- * The combo box to cycle through the built-in presets.
- */
- private static CyderComboBox presetComboBox;
-
- /**
- * The slider to speed up/slow down the simulation.
- */
- private static JSlider iterationsPerSecondSlider;
-
- /**
- * The switch to toggle between detecting oscillations.
- */
- private static CyderSwitch detectOscillationsSwitch;
-
- /**
- * Whether the simulation is running
- */
- private static boolean simulationRunning;
-
- /**
- * The minimum allowable iterations per second.
- */
- private static final int MIN_ITERATIONS_PER_SECOND = 1;
-
- /**
- * The initial and default iterations per second.
- */
- private static final int DEFAULT_ITERATIONS_PER_SECOND = 45;
-
- /**
- * The number of iterations to compute per second.
- */
- private static int iterationsPerSecond = DEFAULT_ITERATIONS_PER_SECOND;
-
- /**
- * The maximum number of iterations per second.
- */
- private static final int MAX_ITERATIONS_PER_SECOND = 100;
-
- /**
- * The current generation the simulation is on.
- */
- private static int generation;
-
- /**
- * The current population of the current state.
- */
- private static int population;
-
- /**
- * The maximum population encountered for this simulation.
- */
- private static int maxPopulation;
-
- /**
- * The generation corresponding to the maximum population.
- */
- private static int correspondingGeneration;
-
- /**
- * The first corresponding generation to achieve the current maximum population.
- */
- private static int firstCorrespondingGeneration;
-
- /**
- * The label to display which generation the simulation is on.
- */
- private static CyderLabel currentGenerationLabel;
-
- /**
- * The label to display the population for the current generation.
- */
- private static CyderLabel currentPopulationLabel;
-
- /**
- * The label to display the maximum population.
- */
- private static CyderLabel maxPopulationLabel;
-
- /**
- * The label to display the generation for the maximum population.
- */
- private static CyderLabel correspondingGenerationLabel;
-
- /**
- * The state the grid was in before the user last pressed start.
- */
- private static ArrayList beforeStartingState;
-
- /**
- * The last state of the grid.
- */
- private static ArrayList lastState = new ArrayList<>();
-
- /**
- * The conway states loaded from static JSON conway directory.
- */
- private static ArrayList correspondingConwayStates;
-
- /**
- * The switcher states to cycle between the states loaded from static JSON conway directory.
- */
- private static ArrayList comboItems;
-
- /**
- * The minimum dimensional node length for the inner cyder grid.
- */
- private static final int MIN_NODES = 50;
-
- /**
- * The width of the widget frame.
- */
- private static final int FRAME_WIDTH = 600;
-
- /**
- * The height of the widget frame.
- */
- private static final int FRAME_HEIGHT = 920;
-
- /**
- * The reset string.
- */
- private static final String RESET = "Reset";
-
- /**
- * The simulate string.
- */
- private static final String SIMULATE = "Simulate";
-
- /**
- * The widget frame title.
- */
- private static final String TITLE = "Conway's Game of Life";
-
- /**
- * The load string.
- */
- private static final String LOAD = "Load";
-
- /**
- * The save string.
- */
- private static final String SAVE = "Save";
-
- /**
- * The clear string.
- */
- private static final String CLEAR = "Clear";
-
- /**
- * The conway string.
- */
- private static final String CONWAY = "conway";
-
- /**
- * The name of the thread which loads conway states.
- */
- private static final String CONWAY_STATE_LOADER_THREAD_NAME = "Conway State Loader";
-
- /**
- * The stop text.
- */
- private static final String STOP = "Stop";
-
- /**
- * The length of the grid.
- */
- private static final int gridLength = 550;
-
- /**
- * The initial node length on the grid.
- */
- private static final int gridNodes = 50;
-
- /**
- * The size of the primary widget controls.
- */
- private static final Dimension primaryControlSize = new Dimension(160, 40);
-
- /**
- * The size of the labels above the grid.
- */
- private static final Dimension topLabelSize = new Dimension(240, 30);
-
- /**
- * The size of the Cyder switches.
- */
- private static final Dimension switchSize = new Dimension(200, 55);
-
- /**
- * The delay in ms between preset combo box actions.
- */
- private static final int presetComboBoxDelay = 800;
-
- /**
- * The last time a preset combo action was invoked.
- */
- private static long lastPresetComboBoxAction = 0;
-
- /**
- * The left and right padding for the slider.
- */
- private static final int sliderPadding = 25;
-
- /**
- * The border length for the grid.
- */
- private static final int gridBorderLength = 3;
-
- /**
- * The length of the grid parent.
- */
- private static final int gridParentLength = gridLength + 2 * gridBorderLength;
-
- @SuppressCyderInspections(CyderInspection.WidgetInspection)
- @Widget(triggers = {CONWAY, "conways", "game of life", "conways game of life"},
- description = "Conway's game of life visualizer")
- public static void showGui() {
- UiUtil.closeIfOpen(conwayFrame);
-
- loadConwayStates();
-
- conwayFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(TITLE)
- .build();
-
- CyderPartitionedLayout partitionedLayout = new CyderPartitionedLayout();
-
- CyderGridLayout topLabelsGrid = new CyderGridLayout(2, 2);
-
- currentPopulationLabel = new CyderLabel();
- currentPopulationLabel.setSize(topLabelSize);
- topLabelsGrid.addComponent(currentPopulationLabel);
-
- maxPopulationLabel = new CyderLabel();
- maxPopulationLabel.setSize(topLabelSize);
- topLabelsGrid.addComponent(maxPopulationLabel);
-
- currentGenerationLabel = new CyderLabel();
- currentGenerationLabel.setSize(topLabelSize);
- topLabelsGrid.addComponent(currentGenerationLabel);
-
- correspondingGenerationLabel = new CyderLabel();
- correspondingGenerationLabel.setSize(topLabelSize);
- topLabelsGrid.addComponent(correspondingGenerationLabel);
-
- partitionedLayout.spacer(1);
-
- CyderPanel topLabelsPanel = new CyderPanel(topLabelsGrid);
- topLabelsPanel.setSize((int) (FRAME_WIDTH / 1.5), 50);
- partitionedLayout.addComponentMaintainSize(topLabelsPanel, CyderPartitionedLayout.PartitionAlignment.TOP);
-
- partitionedLayout.spacer(0.5f);
-
- conwayGrid = new CyderGrid(gridNodes, gridLength);
- conwayGrid.setSize(gridLength, gridLength);
- conwayGrid.setMinNodes(MIN_NODES);
- conwayGrid.setMaxNodes(150);
- conwayGrid.setDrawGridLines(false);
- conwayGrid.setBackground(CyderColors.vanilla);
- conwayGrid.setResizable(true);
- conwayGrid.setSmoothScrolling(true);
- conwayGrid.installClickAndDragPlacer();
- conwayGrid.setSaveStates(false);
- conwayGrid.setLocation(gridBorderLength, gridBorderLength);
-
- JLabel conwayGridParent = new JLabel();
- conwayGridParent.setBorder(new LineBorder(CyderColors.navy, gridBorderLength));
- conwayGridParent.setSize(gridParentLength, gridParentLength);
- conwayGridParent.add(conwayGrid);
- partitionedLayout.addComponentMaintainSize(conwayGridParent, CyderPartitionedLayout.PartitionAlignment.TOP);
-
- partitionedLayout.spacer(1);
-
- CyderGridLayout primaryControlGrid = new CyderGridLayout(2, 3);
-
- stopSimulationButton = new CyderButton(SIMULATE);
- stopSimulationButton.setSize(primaryControlSize);
- stopSimulationButton.addActionListener(e -> stopSimulationButtonAction());
- primaryControlGrid.addComponent(stopSimulationButton);
-
- CyderButton resetButton = new CyderButton(RESET);
- resetButton.setSize(primaryControlSize);
- resetButton.addActionListener(e -> resetToPreviousState());
- primaryControlGrid.addComponent(resetButton);
-
- CyderButton loadButton = new CyderButton(LOAD);
- loadButton.setSize(primaryControlSize);
- loadButton.addActionListener(e -> loadButtonAction());
- primaryControlGrid.addComponent(loadButton);
-
- presetComboBox = new CyderComboBox(primaryControlSize.width, primaryControlSize.height,
- comboItems, comboItems.get(0));
- presetComboBox.getIterationButton().addActionListener(e -> presetComboBoxAction());
- presetComboBox.setSize(primaryControlSize);
- primaryControlGrid.addComponent(presetComboBox);
-
- CyderButton clearButton = new CyderButton(CLEAR);
- clearButton.setSize(primaryControlSize);
- clearButton.addActionListener(e -> resetSimulation());
- primaryControlGrid.addComponent(clearButton);
-
- CyderButton saveButton = new CyderButton(SAVE);
- saveButton.setSize(primaryControlSize);
- saveButton.addActionListener(e -> toFile());
- primaryControlGrid.addComponent(saveButton);
-
- CyderPanel primaryControlPanel = new CyderPanel(primaryControlGrid);
- primaryControlPanel.setSize(450, 140);
- partitionedLayout.addComponentMaintainSize(primaryControlPanel);
-
- CyderGridLayout switchGrid = new CyderGridLayout(2, 1);
-
- detectOscillationsSwitch = new CyderSwitch(switchSize, CyderSwitchState.ON);
- detectOscillationsSwitch.setSize(switchSize);
- detectOscillationsSwitch.setState(CyderSwitchState.ON);
- detectOscillationsSwitch.setButtonPercent(50);
- detectOscillationsSwitch.setOnText("Oscillations");
- detectOscillationsSwitch.setOffText("Ignore");
- switchGrid.addComponent(detectOscillationsSwitch);
-
- CyderSwitch drawGridLinesSwitch = new CyderSwitch(switchSize, CyderSwitchState.OFF);
- drawGridLinesSwitch.setSize(switchSize);
- drawGridLinesSwitch.getSwitchButton().addActionListener(e -> {
- CyderSwitchState nextState = drawGridLinesSwitch.getNextState();
- conwayGrid.setDrawGridLines(nextState.equals(CyderSwitchState.ON));
- conwayGrid.repaint();
- });
- drawGridLinesSwitch.setOffText("No Grid");
- drawGridLinesSwitch.setOnText("Grid");
- drawGridLinesSwitch.setButtonPercent(50);
- switchGrid.addComponent(drawGridLinesSwitch);
-
- CyderPanel switchGridPanel = new CyderPanel(switchGrid);
- switchGridPanel.setSize(450, 60);
- partitionedLayout.addComponentMaintainSize(switchGridPanel);
-
- iterationsPerSecondSlider = new JSlider(JSlider.HORIZONTAL, MIN_ITERATIONS_PER_SECOND,
- MAX_ITERATIONS_PER_SECOND, DEFAULT_ITERATIONS_PER_SECOND);
- CyderSliderUi sliderUi = new CyderSliderUi(iterationsPerSecondSlider);
- sliderUi.setThumbStroke(new BasicStroke(2.0f));
- sliderUi.setThumbRadius(25);
- sliderUi.setThumbShape(ThumbShape.CIRCLE);
- sliderUi.setThumbFillColor(Color.black);
- sliderUi.setThumbOutlineColor(CyderColors.navy);
- sliderUi.setRightThumbColor(CyderColors.regularBlue);
- sliderUi.setLeftThumbColor(CyderColors.regularPink);
- sliderUi.setTrackStroke(new BasicStroke(3.0f));
- iterationsPerSecondSlider.setUI(sliderUi);
- iterationsPerSecondSlider.setSize(350, 40);
- iterationsPerSecondSlider.setPaintTicks(false);
- iterationsPerSecondSlider.setPaintLabels(false);
- iterationsPerSecondSlider.setVisible(true);
- iterationsPerSecondSlider.addChangeListener(e -> iterationsSliderChangeAction());
- iterationsPerSecondSlider.setOpaque(false);
- iterationsPerSecondSlider.setToolTipText("Iterations per second");
- iterationsPerSecondSlider.setFocusable(false);
- iterationsPerSecondSlider.repaint();
- iterationsPerSecondSlider.setSize(FRAME_WIDTH - 2 * sliderPadding, 40);
-
- partitionedLayout.spacer(0.5f);
- partitionedLayout.addComponentMaintainSize(iterationsPerSecondSlider);
- partitionedLayout.spacer(0.5f);
-
- resetSimulation();
- conwayFrame.setCyderLayout(partitionedLayout);
- conwayFrame.finalizeAndShow();
- }
-
- /**
- * The actions to invoke when a change of the iterations slider is encountered.
- */
- @ForReadability
- private static void iterationsSliderChangeAction() {
- iterationsPerSecond = iterationsPerSecondSlider.getValue();
- }
-
- /**
- * The actions to invoke when the present combo box button is clicked.
- */
- @ForReadability
- private static void presetComboBoxAction() {
- long now = System.currentTimeMillis();
- if (lastPresetComboBoxAction + presetComboBoxDelay > now) return;
- lastPresetComboBoxAction = now;
-
- CyderComboBoxState nextState = presetComboBox.getNextState();
-
- for (int i = 0 ; i < comboItems.size() ; i++) {
- if (comboItems.get(i).equals(nextState)) {
- beforeStartingState = new ArrayList<>();
-
- correspondingConwayStates.get(i).getNodes().forEach(point ->
- beforeStartingState.add(new GridNode((int) point.getX(), (int) point.getY())));
-
- conwayFrame.revokeAllNotifications();
- conwayFrame.notify("Loaded state: " + correspondingConwayStates.get(i).getName());
- conwayGrid.setNodeDimensionLength(correspondingConwayStates.get(i).getGridSize());
-
- break;
- }
- }
-
- resetToPreviousState();
- }
-
- /**
- * The actions to invoke when the load button is pressed.
- */
- @ForReadability
- private static void loadButtonAction() {
- CyderThreadRunner.submit(() -> {
- Optional optionalFile = GetterUtil.getInstance().getFile(new GetFileBuilder("Load state")
- .setRelativeTo(conwayFrame));
- if (optionalFile.isEmpty()) return;
- File file = optionalFile.get();
-
- if (file.exists() && FileUtil.validateExtension(file, Extension.JSON.getExtension())) {
- fromJson(file);
- }
- }, CONWAY_STATE_LOADER_THREAD_NAME);
- }
-
- /**
- * The actions to invoke when the stop simulation button is clicked.
- */
- @ForReadability
- private static void stopSimulationButtonAction() {
- if (simulationRunning) {
- stopSimulation();
- } else if (conwayGrid.getNodeCount() > 0) {
- simulationRunning = true;
- stopSimulationButton.setText(STOP);
- conwayGrid.uninstallClickAndDragPlacer();
- conwayGrid.setResizable(false);
- start();
- } else {
- conwayFrame.notify("Place at least one node");
- }
- }
-
- /**
- * Resets the simulation and all values back to their default.
- */
- private static void resetSimulation() {
- stopSimulation();
-
- iterationsPerSecond = DEFAULT_ITERATIONS_PER_SECOND;
-
- conwayGrid.setNodeDimensionLength(50);
- conwayGrid.clearGrid();
- conwayGrid.repaint();
-
- detectOscillationsSwitch.setState(CyderSwitchState.ON);
- iterationsPerSecondSlider.setValue(DEFAULT_ITERATIONS_PER_SECOND);
- iterationsPerSecond = DEFAULT_ITERATIONS_PER_SECOND;
-
- beforeStartingState = null;
-
- resetStats();
- }
-
- /**
- * Resets the population/generation statistics and labels.
- */
- private static void resetStats() {
- generation = 0;
- population = 0;
- maxPopulation = 0;
- correspondingGeneration = 0;
- firstCorrespondingGeneration = 0;
-
- updateLabels();
- }
-
- /**
- * Updates the statistic labels based on the currently set values.
- */
- public static void updateLabels() {
- currentGenerationLabel.setText("Generation: " + generation);
- currentPopulationLabel.setText("Population: " + population);
- maxPopulationLabel.setText("Max Population: " + maxPopulation);
-
- if (firstCorrespondingGeneration == 0 || firstCorrespondingGeneration == generation) {
- correspondingGenerationLabel.setText("Corr Gen: " + correspondingGeneration);
- } else {
- correspondingGenerationLabel.setText("Corr Gen: " + correspondingGeneration
- + ", first: " + firstCorrespondingGeneration);
- }
- }
-
- /**
- * Sets the grid to the state it was in before beginning the simulation.
- */
- private static void resetToPreviousState() {
- if (beforeStartingState == null) return;
-
- stopSimulation();
-
- conwayGrid.setGridState(beforeStartingState);
- conwayGrid.repaint();
-
- resetStats();
- population = beforeStartingState.size();
- updateLabels();
- }
-
- /**
- * Performs any stopping actions needed to properly stop the simulation.
- */
- private static void stopSimulation() {
- simulationRunning = false;
- stopSimulationButton.setText(SIMULATE);
- conwayGrid.installClickAndDragPlacer();
- conwayGrid.setResizable(true);
- }
-
- /**
- * The name of the conway simulation thread.
- */
- private static final String CONWAY_SIMULATOR_THREAD_NAME = "Conway Simulator";
-
- /**
- * Starts the simulation.
- */
- private static void start() {
- beforeStartingState = new ArrayList<>(conwayGrid.getGridNodes());
-
- CyderThreadRunner.submit(() -> {
- while (simulationRunning) {
- try {
- ArrayList nextState = new ArrayList<>();
-
- int[][] nextGen = nextGeneration(cyderGridToConwayGrid(conwayGrid.getGridNodes()));
- for (int i = 0 ; i < nextGen.length ; i++) {
- for (int j = 0 ; j < nextGen[0].length ; j++) {
- if (nextGen[i][j] == 1) {
- nextState.add(new GridNode(i, j));
- }
- }
- }
-
- if (nextState.equals(conwayGrid.getGridNodes())) {
- conwayFrame.revokeAllNotifications();
- conwayFrame.notify("Simulation stabilized at generation: " + generation);
- stopSimulation();
- return;
- } else if (detectOscillationsSwitch.getState().equals(CyderSwitchState.ON)
- && nextState.equals(lastState)) {
- conwayFrame.revokeAllNotifications();
- conwayFrame.notify("Detected oscillation at generation: " + generation);
- stopSimulation();
- return;
- } else if (nextState.isEmpty()) {
- conwayFrame.revokeAllNotifications();
- conwayFrame.notify("Simulation ended with total elimination at generation: "
- + generation);
- stopSimulation();
- return;
- }
-
- // advance last state
- lastState = new ArrayList<>(conwayGrid.getGridNodes());
-
- // set new state
- conwayGrid.setGridNodes(nextState);
- conwayGrid.repaint();
-
- generation++;
- population = nextState.size();
-
- if (population > maxPopulation) {
- firstCorrespondingGeneration = generation;
-
- maxPopulation = population;
- correspondingGeneration = generation;
- } else if (population == maxPopulation) {
- correspondingGeneration = generation;
- }
-
- updateLabels();
- ThreadUtil.sleep((long) (TimeUtil.millisInSecond / iterationsPerSecond));
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }
- }, CONWAY_SIMULATOR_THREAD_NAME);
- }
-
- /**
- * Loads the conway state from the provided json file and sets the current grid state to it.
- *
- * @param jsonFile the json file to load the state from
- */
- private static void fromJson(File jsonFile) {
- Preconditions.checkNotNull(jsonFile);
- Preconditions.checkArgument(jsonFile.exists());
-
- try {
- Reader reader = new FileReader(jsonFile);
- ConwayState loadState = SerializationUtil.fromJson(reader, ConwayState.class);
- reader.close();
-
- resetSimulation();
-
- conwayGrid.setNodeDimensionLength(loadState.getGridSize());
- loadState.getNodes().forEach(point -> conwayGrid.addNode(
- new GridNode((int) point.getX(), (int) point.getY())));
-
- conwayFrame.notify("Loaded state: " + loadState.getName());
- beforeStartingState = new ArrayList<>(conwayGrid.getGridNodes());
-
- resetStats();
- population = loadState.getNodes().size();
- updateLabels();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- conwayFrame.notify("Could not parse json as a valid ConwayState object");
- }
- }
-
- /**
- * The name of the thread to save a conway grid state.
- */
- private static final String CONWAY_STATE_SAVER_THREAD_NAME = "Conway State Saver";
-
- /**
- * Saves the current grid state to a json which can be loaded.
- */
- private static void toFile() {
- CyderThreadRunner.submit(() -> {
- if (conwayGrid.getNodeCount() == 0) {
- conwayFrame.notify("Place at least one node");
- return;
- }
-
- Optional optionalSaveName = GetterUtil.getInstance().getInput(
- new GetInputBuilder("Save name", "Save Conway state file name")
- .setRelativeTo(conwayFrame)
- .setFieldHintText("Valid filename")
- .setSubmitButtonText("Save Conway State"));
- if (optionalSaveName.isEmpty()) return;
- String saveName = optionalSaveName.get();
-
- String filename = saveName + Extension.JSON.getExtension();
-
- if (FileUtil.isValidFilename(filename)) {
- File saveFile = UserUtil.createFileInUserSpace(filename);
-
- ArrayList points = new ArrayList<>();
-
- conwayGrid.getGridNodes().forEach(node -> points.add(new Point(node.getX(), node.getY())));
- ConwayState state = new ConwayState(saveName, conwayGrid.getNodeDimensionLength(), points);
-
- try {
- FileWriter writer = new FileWriter(saveFile);
- SerializationUtil.toJson(state, writer);
- writer.close();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- conwayFrame.notify("Save state failed");
- }
- } else {
- conwayFrame.notify("Invalid save name");
- }
- }, CONWAY_STATE_SAVER_THREAD_NAME);
- }
-
- /**
- * Converts the CyderGrid nodes to a 2D integer array
- * needed to compute the next Conway iteration.
- *
- * @param nodes the list of cyder grid nodes
- * @return the 2D array consisting of 1s and 0s
- */
- private static int[][] cyderGridToConwayGrid(Collection nodes) {
- int len = conwayGrid.getNodeDimensionLength();
-
- int[][] ret = new int[len][len];
- nodes.forEach(node -> {
- int x = node.getX();
- int y = node.getY();
-
- if (x < len && y < len) {
- ret[x][y] = 1;
- }
- });
- return ret;
- }
-
- /**
- * Computes the next generation based on the current generation.
- *
- * @param currentGeneration the current generation
- * @return the next generation
- */
- private static int[][] nextGeneration(int[][] currentGeneration) {
- Preconditions.checkNotNull(currentGeneration);
- Preconditions.checkArgument(currentGeneration.length >= MIN_NODES);
- Preconditions.checkArgument(currentGeneration[0].length >= MIN_NODES);
-
- int[][] ret = new int[currentGeneration.length][currentGeneration[0].length];
-
- for (int l = 1 ; l < currentGeneration.length - 1 ; l++) {
- for (int m = 1 ; m < currentGeneration[0].length - 1 ; m++) {
- int aliveNeighbours = 0;
- for (int i = -1 ; i <= 1 ; i++) {
- for (int j = -1 ; j <= 1 ; j++) {
- aliveNeighbours += currentGeneration[l + i][m + j];
- }
- }
-
- aliveNeighbours -= currentGeneration[l][m];
-
- if ((currentGeneration[l][m] == 1) && (aliveNeighbours < 2)) {
- ret[l][m] = 0;
- } else if ((currentGeneration[l][m] == 1) && (aliveNeighbours > 3)) {
- ret[l][m] = 0;
- } else if ((currentGeneration[l][m] == 0) && (aliveNeighbours == 3)) {
- ret[l][m] = 1;
- } else {
- ret[l][m] = currentGeneration[l][m];
- }
- }
- }
-
- return ret;
- }
-
- /**
- * Loads the preset conway states from static JSON conway.
- */
- private static void loadConwayStates() {
- comboItems = new ArrayList<>();
- correspondingConwayStates = new ArrayList<>();
-
- File statesDir = StaticUtil.getStaticDirectory(CONWAY);
-
- if (statesDir.exists()) {
- File[] statesDirFiles = statesDir.listFiles();
-
- if (ArrayUtil.nullOrEmpty(statesDirFiles)) {
- presetComboBox.getIterationButton().setEnabled(false);
- return;
- }
-
- Arrays.stream(statesDirFiles).filter(jsonStateFile ->
- FileUtil.validateExtension(jsonStateFile, Extension.JSON.getExtension()))
- .forEach(jsonStateFile -> {
- try {
- Reader reader = new FileReader(jsonStateFile);
- ConwayState loadState = SerializationUtil.fromJson(reader, ConwayState.class);
- reader.close();
-
- correspondingConwayStates.add(loadState);
- comboItems.add(new CyderComboBoxState(loadState.getName()));
- } catch (Exception e) {
- Logger.log(LogTag.SYSTEM_IO, "Failed to load conway state: " + jsonStateFile);
- ExceptionHandler.handle(e);
- }
- });
- }
- }
-
- /**
- * An object used to store a Conway's game of life grid state.
- */
- @SuppressWarnings("ClassCanBeRecord") /* GSON */
- @Immutable
- private static class ConwayState {
- /**
- * The name of the conway state.
- */
- private final String name;
-
- /**
- * The grid length for the saved state.
- */
- private final int gridSize;
-
- /**
- * The list of nodes for the saves state.
- */
- private final ArrayList nodes;
-
- /**
- * Constructs a new conway state.
- *
- * @param name the name of the state
- * @param gridSize the size of the nxn grid
- * @param nodes the nodes to place for the state
- */
- public ConwayState(String name, int gridSize, ArrayList nodes) {
- this.name = Preconditions.checkNotNull(name);
- this.gridSize = gridSize;
- this.nodes = Preconditions.checkNotNull(nodes);
- }
-
- /**
- * Returns the name of this conway state.
- *
- * @return the name of this conway state
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the grid size of this conway state.
- *
- * @return the grid size of this conway state
- */
- public int getGridSize() {
- return gridSize;
- }
-
- /**
- * Returns the list of points for this conway state.
- *
- * @return the list of points for this conway state
- */
- public ArrayList getNodes() {
- return nodes;
- }
- }
-}
diff --git a/src/main/java/cyder/widgets/HashingWidget.java b/src/main/java/cyder/widgets/HashingWidget.java
deleted file mode 100644
index 1ba4cd070..000000000
--- a/src/main/java/cyder/widgets/HashingWidget.java
+++ /dev/null
@@ -1,201 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderFonts;
-import cyder.constants.HtmlTags;
-import cyder.handlers.internal.InformHandler;
-import cyder.logging.LogTag;
-import cyder.logging.Logger;
-import cyder.strings.CyderStrings;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderPasswordField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.label.CyderLabel;
-import cyder.ui.selection.CyderCheckbox;
-import cyder.ui.selection.CyderComboBox;
-import cyder.ui.selection.CyderComboBoxState;
-import cyder.utils.OsUtil;
-import cyder.utils.SecurityUtil;
-
-/**
- * A widget for computing the hash of strings.
- */
-@Vanilla
-@CyderAuthor
-public class HashingWidget {
- /**
- * The hash field.
- */
- private CyderPasswordField hashField;
-
- /**
- * The hash algorithm combo box.
- */
- private CyderComboBox comboBox;
-
- /**
- * The widget description.
- */
- private static final String description = "A hashing widget to hash any string using"
- + " multiple algorithms such as MD5, SHA256, and SHA1";
-
- /**
- * Constructs and returns a new hashing widget.
- *
- * @return a new hashing widget
- */
- public static HashingWidget getInstance() {
- return new HashingWidget();
- }
-
- /**
- * Constructs a new hashing widget.
- */
- private HashingWidget() {
- Logger.log(LogTag.OBJECT_CREATION, this);
- }
-
- /**
- * Shows a new instance of the hashing widget.
- */
- @Widget(triggers = {HASH, "hasher"}, description = description)
- public static void showGui() {
- getInstance().innerShowGui();
- }
-
- /**
- * The hash string.
- */
- private static final String HASH = "Hash";
-
- /**
- * The id of the sha256 algorithm.
- */
- private static final String SHA_256 = "SHA-256";
-
- /**
- * The id of the sha1 algorithm.
- */
- private static final String SHA_1 = "SHA-1";
-
- /**
- * The id of the md5 algorithm.
- */
- private static final String MD5 = "MD5";
-
- /**
- * The valid hashing algorithms for the combo box chooser.
- */
- private static final ImmutableList HASH_ALGORITHMS = ImmutableList.of(
- new CyderComboBoxState(SHA_256, "SHA256 Algorithm"),
- new CyderComboBoxState(SHA_1, "SHA-1 Algorithm"),
- new CyderComboBoxState(MD5, "MD5 Algorithm (Do not use for passwords)")
- );
-
- /**
- * The text of the hash result popup.
- */
- private static final String HASH_RESULT = HASH + CyderStrings.space + "Result";
-
- /**
- * The title of the frame.
- */
- private static final String TITLE = "Hasher";
-
- /**
- * The width of the frame.
- */
- private static final int FRAME_WIDTH = 500;
-
- /**
- * The height of the frame.
- */
- private static final int FRAME_HEIGHT = 260;
-
- /**
- * The checkbox for whether to save the hash result to the clipboard.
- */
- private CyderCheckbox saveToClipboardCheckbox;
-
- /**
- * Shows the gui for this instance of the hashing widget.
- */
- public void innerShowGui() {
- CyderFrame hashFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(TITLE)
- .build();
-
- CyderLabel Instructions = new CyderLabel("Enter input to be hashed");
- Instructions.setFont(CyderFonts.SEGOE_20);
- Instructions.setBounds(65, 40, 400, 30);
- hashFrame.getContentPane().add(Instructions);
-
- hashField = new CyderPasswordField();
- hashField.setToolTipText("Hold shift to reveal contents");
- hashField.addActionListener(e -> hashButtonAction());
- hashField.setBounds(50, 90, 400, 40);
- hashFrame.getContentPane().add(hashField);
-
- CyderButton hashButton = new CyderButton(HASH);
- hashButton.addActionListener(e -> hashButtonAction());
- hashButton.setBounds(50, 140, 180, 40);
- hashFrame.getContentPane().add(hashButton);
-
- saveToClipboardCheckbox = new CyderCheckbox();
- saveToClipboardCheckbox.setChecked();
- saveToClipboardCheckbox.setLocation(hashFrame.getWidth() / 2 + 70, 190);
- hashFrame.getContentPane().add(saveToClipboardCheckbox);
-
- CyderLabel saveToClipBoardLabel = new CyderLabel("Copy hash to clipboard:");
- saveToClipBoardLabel.setBounds(120, 200, 200, 30);
- hashFrame.getContentPane().add(saveToClipBoardLabel);
-
- comboBox = new CyderComboBox(210, 40, HASH_ALGORITHMS, HASH_ALGORITHMS.get(0));
- comboBox.setBounds(240, 140, 210, 40);
- hashFrame.getContentPane().add(comboBox);
-
- hashFrame.finalizeAndShow();
- }
-
- /**
- * The action to invoke when the hash button is pressed.
- */
- private void hashButtonAction() {
- char[] hashFieldContents = hashField.getPassword();
- if (hashFieldContents.length == 0) return;
-
- String algorithm = comboBox.getCurrentState().getDisplayValue();
- String hashResult = switch (algorithm) {
- case SHA_256 -> SecurityUtil.toHexString(SecurityUtil.getSha256(hashFieldContents));
- case SHA_1 -> SecurityUtil.toHexString(SecurityUtil.getSha1(hashFieldContents));
- case MD5 -> SecurityUtil.toHexString(SecurityUtil.getMd5(hashFieldContents));
- default -> throw new IllegalStateException("Unimplemented hash algorithm: " + algorithm);
- };
-
- String informText = "Your hashed input is:" + HtmlTags.breakTag + hashResult
- + HtmlTags.breakTag + "Provided by " + algorithm;
- if (saveToClipboardCheckbox.isChecked()) {
- OsUtil.setClipboard(hashResult);
- }
-
- new InformHandler.Builder(informText)
- .setTitle(algorithm + CyderStrings.space + HASH_RESULT)
- .setRelativeTo(hashField).inform();
-
- reset();
- }
-
- /**
- * Resets the widget.
- */
- @ForReadability
- private void reset() {
- hashField.setText("");
- }
-}
diff --git a/src/main/java/cyder/widgets/ImageAveragerWidget.java b/src/main/java/cyder/widgets/ImageAveragerWidget.java
deleted file mode 100644
index 781212be9..000000000
--- a/src/main/java/cyder/widgets/ImageAveragerWidget.java
+++ /dev/null
@@ -1,498 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.*;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.enumerations.CyderInspection;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.getter.GetFileBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.drag.button.DragLabelTextButton;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.list.CyderScrollList;
-import cyder.user.UserDataManager;
-import cyder.user.UserFile;
-import cyder.utils.ImageUtil;
-
-import javax.imageio.ImageIO;
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferByte;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
-
-/**
- * A widget to average images together.
- */
-@Vanilla
-@CyderAuthor
-public final class ImageAveragerWidget {
- /**
- * The scroll label for the selected images.
- */
- private static JLabel imagesScrollLabel;
-
- /**
- * The actual scroll container to hold the scroll label.
- */
- private static CyderScrollList imagesScroll;
-
- /**
- * The averaging frame.
- */
- private static CyderFrame averagerFrame;
-
- /**
- * The component to hold the scroll on top of it.
- */
- private static JLabel imageScrollLabelHolder;
-
- /**
- * Suppress default constructor.
- */
- private ImageAveragerWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The widget description.
- */
- private static final String description = "A widget that adds multiple images "
- + "together and divides by the total to obtain an average base image";
-
- /**
- * The title of the widget frame.
- */
- private static final String FRAME_TITLE = "Image Averager";
-
- /**
- * The save text.
- */
- private static final String SAVE = "Save";
-
- /**
- * The save image text.
- */
- private static final String SAVE_IMAGE = "Save Image";
-
- /**
- * The width of the widget frame.
- */
- private static final int FRAME_WIDTH = 600;
-
- /**
- * The height of the widget frame.
- */
- private static final int FRAME_HEIGHT = 640;
-
- /**
- * The length of the images scroll list.
- */
- private static final int imagesScrollLen = 400;
-
- /**
- * The builder for the getter util instance to add a file.
- */
- private static final GetFileBuilder builder = new GetFileBuilder("Select any image file")
- .setRelativeTo(averagerFrame);
-
- /**
- * The maximum image length that the preview frame can display.
- */
- private static final int maxImageLength = 800;
-
- /**
- * The combined files name separator.
- */
- private static final String UNDERSCORE = "_";
-
- /**
- * The add image button text.
- */
- private static final String ADD_IMAGE = "Add Image";
-
- /**
- * The remove images button text.
- */
- private static final String REMOVE_IMAGES = "Remove Selected Images";
-
- /**
- * The average images button text.
- */
- private static final String AVERAGE_IMAGES = "Average Images";
-
- /**
- * The thread name for the waiter thread for the add file getter.
- */
- private static final String IMAGE_AVERAGER_ADD_FILE_WAITER_THREAD_NAME = "Image Averager Add File Waiter";
-
- /**
- * The alpha value for pixels with a non-present alpha value.
- */
- private static final int EMPTY_ALPHA = 16777216;
-
- /**
- * The length of data for data elements containing an alpha byte.
- */
- private static final int alphaPixelLength = 4;
-
- /**
- * The length of data for data elements without an alpha byte.
- */
- private static final int noAlphaPixelLength = 3;
-
- /**
- * Shows the image averaging widget.
- */
- @SuppressCyderInspections(CyderInspection.WidgetInspection)
- @Widget(triggers = {"average images", "average pictures"}, description = description)
- public static void showGui() {
- UiUtil.closeIfOpen(averagerFrame);
-
- averagerFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(FRAME_TITLE)
- .build();
-
- imagesScroll = new CyderScrollList(imagesScrollLen, imagesScrollLen, CyderScrollList.SelectionPolicy.MULTIPLE);
- imagesScroll.setBorder(null);
-
- imageScrollLabelHolder = new JLabel();
- imageScrollLabelHolder.setBounds(90, 40, 420, 420);
- imageScrollLabelHolder.setBorder(new LineBorder(CyderColors.navy, 5));
- averagerFrame.getContentPane().add(imageScrollLabelHolder);
-
- imagesScrollLabel = imagesScroll.generateScrollList();
- imagesScrollLabel.setBounds(10, 10, imagesScrollLen, imagesScrollLen);
- imageScrollLabelHolder.add(imagesScrollLabel);
-
- imageScrollLabelHolder.setBackground(Color.white);
- imagesScrollLabel.setOpaque(true);
- imageScrollLabelHolder.setOpaque(true);
- imagesScrollLabel.setBackground(Color.white);
-
- CyderButton addFileButton = new CyderButton(ADD_IMAGE);
- addFileButton.setBounds(90, 480, 420, 40);
- averagerFrame.getContentPane().add(addFileButton);
- addFileButton.addActionListener(e -> addButtonAction());
-
- CyderButton removeSelectedImagesButton = new CyderButton(REMOVE_IMAGES);
- removeSelectedImagesButton.setBounds(90, 530, 420, 40);
- averagerFrame.getContentPane().add(removeSelectedImagesButton);
- removeSelectedImagesButton.addActionListener(e -> removeSelectedImagesButtonAction());
-
- CyderButton average = new CyderButton(AVERAGE_IMAGES);
- average.setBackground(CyderColors.regularPink);
- average.setBounds(90, 580, 420, 40);
- averagerFrame.getContentPane().add(average);
- average.addActionListener(e -> averageButtonAction());
-
- averagerFrame.finalizeAndShow();
- }
-
- /**
- * The action to invoke when the remove selected images button is pressed.
- */
- @ForReadability
- private static void removeSelectedImagesButtonAction() {
- ImmutableList selectedElements = imagesScroll.getSelectedElements();
- for (String selectedElement : selectedElements) {
- currentFiles.remove(selectedElement);
- }
-
- imagesScroll.removeSelectedElements();
- revalidateImagesScroll();
- }
-
- private static final HashMap currentFiles = new HashMap<>();
-
- /**
- * Revalidates the chosen images scroll view.
- */
- private static void revalidateImagesScroll() {
- imagesScroll.removeAllElements();
- imageScrollLabelHolder.remove(imagesScrollLabel);
-
- currentFiles.forEach((filename, file) -> {
- Runnable openFileRunnable = () -> FileUtil.openResource(file.getAbsolutePath(), true);
- imagesScroll.addElementWithDoubleClickAction(filename, openFileRunnable);
- });
-
- imagesScrollLabel = imagesScroll.generateScrollList();
- imagesScrollLabel.setBounds(10, 10, imagesScrollLen, imagesScrollLen);
- imageScrollLabelHolder.setBackground(CyderColors.vanilla);
-
- imageScrollLabelHolder.add(imagesScrollLabel);
-
- imageScrollLabelHolder.revalidate();
- imageScrollLabelHolder.repaint();
-
- averagerFrame.revalidate();
- averagerFrame.repaint();
- }
-
- /**
- * The action to invoke when the add file button is pressed.
- */
- private static void addButtonAction() {
- CyderThreadRunner.submit(() -> {
- try {
- Optional optionalFile = GetterUtil.getInstance().getFile(builder);
- if (optionalFile.isEmpty()) return;
- File addFile = optionalFile.get();
- if (StringUtil.isNullOrEmpty(FileUtil.getFilename(addFile))) return;
-
- boolean supportedImage = FileUtil.isSupportedImageExtension(addFile);
- if (!supportedImage) {
- averagerFrame.notify("Selected file is not a supported image file");
- return;
- }
-
- currentFiles.put(addFile.getName(), addFile);
- revalidateImagesScroll();
- } catch (Exception ex) {
- ExceptionHandler.handle(ex);
- }
- }, IMAGE_AVERAGER_ADD_FILE_WAITER_THREAD_NAME);
- }
-
- /**
- * Action performed when the user clicks the compute button.
- */
- private static void averageButtonAction() {
- if (currentFiles.size() < 2) {
- averagerFrame.notify("Please add at least two images");
- return;
- }
-
- AtomicInteger width = new AtomicInteger();
- AtomicInteger height = new AtomicInteger();
-
- currentFiles.forEach((filename, file) -> {
- try {
- BufferedImage currentImage = ImageUtil.read(file);
- width.set(Math.max(currentImage.getWidth(), width.get()));
- height.set(Math.max(currentImage.getHeight(), height.get()));
- } catch (Exception e) {
- averagerFrame.notify("Failed to read image file: " + file.getAbsolutePath());
- }
- });
-
- BufferedImage saveImage = computerAverage(width.get(), height.get());
- ImageIcon previewImage = ImageUtil.resizeIfLengthExceeded(new ImageIcon(saveImage), maxImageLength);
-
- String saveImageName = combineImageNames() + Extension.PNG.getExtension();
- File outputFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.BACKGROUNDS.getName(), saveImageName);
-
- CyderFrame drawFrame = new CyderFrame.Builder()
- .setWidth(previewImage.getIconWidth())
- .setHeight(previewImage.getIconHeight())
- .setBackgroundIcon(previewImage)
- .build();
- DragLabelTextButton saveButton = new DragLabelTextButton.Builder(SAVE)
- .setTooltip(SAVE_IMAGE)
- .setClickAction(() -> {
- boolean saved = saveImage(saveImage, outputFile);
- if (!saved) {
- averagerFrame.notify("Could not save average at this time");
- return;
- }
-
- averagerFrame.notify("Average computed and saved to "
- + StringUtil.getApostropheSuffix(UserDataManager.INSTANCE.getUsername())
- + "backgrounds/ directory");
- drawFrame.dispose(true);
- }).build();
- drawFrame.getTopDragLabel().addRightButton(saveButton, 0);
-
- drawFrame.setVisible(true);
- drawFrame.setLocationRelativeTo(averagerFrame);
- }
-
- /**
- * Saves the provided buffered image to the current user's backgrounds folder using the provided name.
- * Png format is used as the image format.
- *
- * @param saveImage the buffered image to save
- * @param outputFile the file to save the buffered image to
- * @return whether the saving operation was successful
- */
- @ForReadability
- private static boolean saveImage(BufferedImage saveImage, File outputFile) {
- Preconditions.checkNotNull(saveImage);
- Preconditions.checkNotNull(outputFile);
-
- try {
- ImageIO.write(saveImage, Extension.PNG.getExtensionWithoutPeriod(), outputFile);
- return true;
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- return false;
- }
-
- /**
- * Computes the average of the images inside of the files array list and
- * modifies saveImage to have the resulting calculated pixel average.
- *
- * @param width the width of the resulting image
- * @param height the height of the resulting image
- */
- private static BufferedImage computerAverage(int width, int height) {
- BufferedImage saveImage = new BufferedImage(width, height, TYPE_INT_ARGB);
- Graphics2D g2d = saveImage.createGraphics();
- g2d.setPaint(CyderColors.empty);
- g2d.fillRect(0, 0, width, height);
-
- /*
- This should be save to hold the sum of all pixel data.
- Adding a precondition check for file.size() * 256 < Integer.MAX_VALUE
- is even flagged by IntelliJ as always true
- */
- int[][] pixelSum = new int[height][width];
- int[][] divideBy = new int[height][width];
-
- for (int y = 0 ; y < divideBy.length ; y++) {
- for (int x = 0 ; x < divideBy[0].length ; x++) {
- divideBy[y][x] = 0;
- }
- }
-
- ArrayList averageFiles = new ArrayList<>();
- currentFiles.forEach((filename, file) -> averageFiles.add(file));
-
- for (File currentImageFile : averageFiles) {
- BufferedImage currentImage;
- try {
- currentImage = ImageUtil.read(currentImageFile);
- } catch (Exception e) {
- averagerFrame.inform("IO Failure", "Failed to read image file: "
- + currentImageFile.getAbsolutePath());
- ExceptionHandler.handle(e);
- continue;
- }
-
- int currentHeight = currentImage.getHeight();
- int currentWidth = currentImage.getWidth();
-
- int[][] currentPixels = get2DRgbArray(currentImage);
- int currentXOffset = (width - currentWidth) / 2;
- int currentYOffset = (height - currentHeight) / 2;
-
- for (int y = 0 ; y < currentPixels.length ; y++) {
- for (int x = 0 ; x < currentPixels[0].length ; x++) {
- pixelSum[y + currentYOffset][x + currentXOffset] += currentPixels[y][x];
- divideBy[y + currentYOffset][x + currentXOffset] += 1;
- }
- }
- }
-
- for (int y = 0 ; y < pixelSum.length ; y++) {
- for (int x = 0 ; x < pixelSum[0].length ; x++) {
- int dividend = pixelSum[y][x];
- int divisor = divideBy[y][x];
- if (divisor == 0) divisor = 1;
- int quotient = dividend / divisor;
- saveImage.setRGB(x, y, quotient);
- }
- }
-
- return saveImage;
- }
-
- /**
- * Returns a two dimensional integer array representing the pixel data of the provided buffered image.
- *
- * @param image the image to find the pixel data of
- * @return an array of pixel data
- */
- private static int[][] get2DRgbArray(BufferedImage image) {
- byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
-
- int width = image.getWidth();
- int height = image.getHeight();
-
- boolean hasAlphaChannel = image.getAlphaRaster() != null;
- int[][] ret = new int[height][width];
-
- if (hasAlphaChannel) {
- for (int pixel = 0, row = 0, col = 0 ; pixel + 3 < pixels.length ; pixel += alphaPixelLength) {
- int argb = 0;
-
- argb += (((int) pixels[pixel] & 0xff) << 24);
- argb += (((int) pixels[pixel + 3] & 0xff) << 16);
- argb += (((int) pixels[pixel + 2] & 0xff) << 8);
- argb += ((int) pixels[pixel + 1] & 0xff);
-
- ret[row][col] = argb;
- col++;
-
- if (col == width) {
- col = 0;
- row++;
- }
- }
- } else {
- for (int pixel = 0, row = 0, col = 0 ; pixel + 2 < pixels.length ; pixel += noAlphaPixelLength) {
- int argb = 0;
-
- argb -= EMPTY_ALPHA;
- argb += (((int) pixels[pixel + 2] & 0xff) << 16);
- argb += (((int) pixels[pixel + 1] & 0xff) << 8);
- argb += ((int) pixels[pixel] & 0xff);
-
- ret[row][col] = argb;
- col++;
-
- if (col == width) {
- col = 0;
- row++;
- }
- }
- }
-
- return ret;
- }
-
- /**
- * Returns a string of the filenames from the files array
- * list combined and separated by an underscore.
- *
- * @return the combined file names
- */
- @ForReadability
- private static String combineImageNames() {
- StringBuilder ret = new StringBuilder();
-
- int finalIndex = currentFiles.size() - 1;
- AtomicInteger currentIndex = new AtomicInteger();
- currentFiles.forEach((filename, file) -> {
- ret.append(FileUtil.getFilename(file.getName()));
- if (currentIndex.get() != finalIndex) ret.append(UNDERSCORE);
- currentIndex.getAndIncrement();
- });
-
- return ret.toString();
- }
-}
diff --git a/src/main/java/cyder/widgets/ImagePixelatorWidget.java b/src/main/java/cyder/widgets/ImagePixelatorWidget.java
deleted file mode 100644
index b8cbec5ca..000000000
--- a/src/main/java/cyder/widgets/ImagePixelatorWidget.java
+++ /dev/null
@@ -1,386 +0,0 @@
-package cyder.widgets;
-
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.getter.GetFileBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.label.CyderLabel;
-import cyder.user.UserDataManager;
-import cyder.user.UserFile;
-import cyder.utils.ImageUtil;
-
-import javax.imageio.ImageIO;
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.util.Optional;
-
-/**
- * An image pixelator widget.
- */
-@Vanilla
-@CyderAuthor
-public final class ImagePixelatorWidget {
- /**
- * The current icon that is being displayed.
- */
- private static ImageIcon currentDisplayImageIcon;
-
- /**
- * The current raw image file.
- */
- private static File currentFile;
-
- /**
- * The image pixelation preview label.
- */
- private static JLabel previewLabel;
-
- /**
- * The pixelation size field.
- */
- private static CyderTextField pixelSizeField;
-
- /**
- * Suppress default constructor.
- */
- private ImagePixelatorWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The widget description
- */
- private static final String description = "A simple image pixelator widget that transforms"
- + " the image into an image depicted of the specified number of pixels";
-
- /**
- * The width of the frame.
- */
- private static final int FRAME_WIDTH = 700;
-
- /**
- * The height of the frame.
- */
- private static final int FRAME_HEIGHT = 950;
-
- /**
- * The widget frame title.
- */
- private static final String IMAGE_PIXELATOR = "Image Pixelator";
-
- /**
- * The pixel size label text.
- */
- private static final String PIXEL_SIZE = "Pixel Size";
-
- /**
- * The choose image button text.
- */
- private static final String CHOOSE_IMAGE = "Choose Image";
-
- /**
- * The widget frame.
- */
- private static CyderFrame pixelFrame;
-
- /**
- * The border for the preview label.
- */
- private static final LineBorder previewLabelBorder = new LineBorder(CyderColors.navy, 5, false);
-
- /**
- * The maximum length for the preview label image.
- */
- private static final int previewImageMaxLen = 600;
-
- /**
- * The name of the waiter thread for the get file getter util instance.
- */
- private static final String CHOOSE_IMAGE_WAITER_THREAD_NAME = "Choose Image Waiter Thread";
-
- /**
- * The builder for the choose file button.
- */
- private static final GetFileBuilder getterUtilBuilder = new GetFileBuilder("Choose file to resize")
- .setRelativeTo(pixelFrame);
-
- /**
- * The image files text.
- */
- private static final String IMAGE_FILES = "Image files";
-
- /**
- * The pixel label font.
- */
- private static final Font pixelLabelFont = new Font(CyderFonts.AGENCY_FB, Font.BOLD, 28);
-
- /**
- * The approve image label.
- */
- private static final String APPROVE_IMAGE = "Approve Image";
-
- /**
- * The pixelated pixel size part of the name when saving a pixelated image.
- */
- private static final String PIXELATED_PIXEL_SIZE = "_Pixelated_Pixel_Size_";
-
- /**
- * The regex for the pixel size field to restrict the input to numbers.
- */
- private static final String pixelSizeFieldRegexMatcher = "[0-9]*";
-
- /**
- * The length of primary components.
- */
- private static final int componentLength = 300;
-
- /**
- * The height of primary components.
- */
- private static final int componentHeight = 40;
-
- /**
- * The partition length for primary components.
- */
- private static final int componentPartition = 7;
-
- @Widget(triggers = {"pixelate picture", "pixelate image", "pixelator"}, description = description)
- public static void showGui() {
- showGui(null);
- }
-
- /**
- * Shows the widget ui with the provided image as the preview image.
- *
- * @param imageFile the image to pixelate
- */
- public static void showGui(File imageFile) {
- UiUtil.closeIfOpen(pixelFrame);
-
- pixelFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(IMAGE_PIXELATOR)
- .build();
-
- float remainingPartition = CyderPartitionedLayout.MAX_PARTITION - 4 * componentPartition;
-
- CyderPartitionedLayout partitionedLayout = new CyderPartitionedLayout();
- partitionedLayout.setPartitionDirection(CyderPartitionedLayout.PartitionDirection.COLUMN);
-
- CyderLabel pixelSizeLabel = new CyderLabel(PIXEL_SIZE);
- pixelSizeLabel.setFont(pixelLabelFont);
- pixelSizeLabel.setSize(componentLength, componentHeight);
- partitionedLayout.addComponent(pixelSizeLabel, componentPartition);
-
- pixelSizeField = new CyderTextField();
- pixelSizeField.setKeyEventRegexMatcher(pixelSizeFieldRegexMatcher);
- pixelSizeField.setSize(componentLength, componentHeight);
- pixelSizeField.addKeyListener(pixelSizeFieldKeyAdapter);
- partitionedLayout.addComponent(pixelSizeField, componentPartition);
-
- CyderButton chooseImage = new CyderButton(CHOOSE_IMAGE);
- chooseImage.setToolTipText(IMAGE_FILES);
- chooseImage.setSize(componentLength, componentHeight);
- chooseImage.addActionListener(e -> chooseImageButtonAction());
- partitionedLayout.addComponent(chooseImage, componentPartition);
-
- CyderButton approveImageButton = new CyderButton(APPROVE_IMAGE);
- approveImageButton.setSize(componentLength, componentHeight);
- approveImageButton.addActionListener(e -> approveImageAction());
- partitionedLayout.addComponent(approveImageButton, componentPartition);
-
- previewLabel = new JLabel();
- previewLabel.setSize(previewImageMaxLen, previewImageMaxLen);
- previewLabel.setBorder(previewLabelBorder);
- partitionedLayout.addComponent(previewLabel, (int) remainingPartition);
-
- attemptToSetFileAsImage(imageFile);
-
- pixelFrame.setCyderLayout(partitionedLayout);
- pixelFrame.finalizeAndShow();
- }
-
- /**
- * The actions to invoke when the approve image button is pressed.
- */
- private static void approveImageAction() {
- String pixelInput = pixelSizeField.getText();
- if (StringUtil.isNullOrEmpty(pixelInput)) return;
-
- int pixelSize;
- try {
- pixelSize = Integer.parseInt(pixelInput);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- pixelFrame.notify("Could not parse input as an integer:" + pixelInput);
- return;
- }
-
- if (pixelSize == 1) {
- pixelFrame.notify("Pixel size is already 1");
- return;
- }
-
- BufferedImage currentBufferedImage;
- try {
- currentBufferedImage = ImageUtil.read(currentFile);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- pixelFrame.notify("Failed to read image file: " + currentFile.getAbsolutePath());
- return;
- }
-
- BufferedImage saveImage = ImageUtil.pixelateImage(currentBufferedImage, pixelSize);
-
- String currentFilename = FileUtil.getFilename(currentFile);
- String saveName = currentFilename + PIXELATED_PIXEL_SIZE + pixelSize + Extension.PNG.getExtension();
- File saveFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.FILES.getName(), saveName);
-
- try {
- ImageIO.write(saveImage, Extension.PNG.getExtensionWithoutPeriod(), saveFile);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- pixelFrame.notify("Failed to write pixelated image");
- return;
- }
-
- pixelFrame.notify("Successfully saved pixelated image to "
- + StringUtil.getApostropheSuffix(UserDataManager.INSTANCE.getUsername())
- + " files/ directory");
- }
-
- /**
- * The key listener for the pixel size field.
- */
- private static final KeyListener pixelSizeFieldKeyAdapter = new KeyAdapter() {
- @Override
- public void keyReleased(KeyEvent e) {
- try {
- String input = pixelSizeField.getText();
- if (input.isEmpty()) return;
-
- int pixelSize = -1;
- try {
- pixelSize = Integer.parseInt(pixelSizeField.getText());
- } catch (Exception ex) {
- ExceptionHandler.handle(ex);
- }
-
- if (pixelSize == -1) {
- pixelFrame.notify("Could not parse input as integer: " + input);
- return;
- }
-
- if (pixelSize == 0 || pixelSize == 1) return;
-
- BufferedImage bufferedImage = ImageUtil.pixelateImage(ImageUtil.read(currentFile), pixelSize);
- currentDisplayImageIcon = ImageUtil.resizeIfLengthExceeded(
- ImageUtil.toImageIcon(bufferedImage), previewImageMaxLen);
- previewLabel.setIcon(currentDisplayImageIcon);
-
- refreshPreviewLabelSize();
- repaintPreviewLabelAndFrame();
- } catch (Exception ex) {
- ExceptionHandler.handle(ex);
- }
- }
- };
-
- /**
- * The actions to invoke when the choose image button is pressed.
- */
- @ForReadability
- private static void chooseImageButtonAction() {
- CyderThreadRunner.submit(() -> {
- Optional optionalFile = GetterUtil.getInstance().getFile(getterUtilBuilder);
- if (optionalFile.isEmpty()) return;
- attemptToSetFileAsImage(optionalFile.get());
- }, CHOOSE_IMAGE_WAITER_THREAD_NAME);
- }
-
- /**
- * Attempts to read the provided file and set it as the current image file to be pixelated.
- *
- * @param imageFile the file to read and set as the current image file to be pixelated
- */
- @ForReadability
- private static void attemptToSetFileAsImage(File imageFile) {
- if (imageFile == null || !imageFile.exists() || !FileUtil.isSupportedImageExtension(imageFile)) {
- currentFile = null;
- currentDisplayImageIcon = null;
-
- repaintPreviewLabelAndFrame();
-
- return;
- }
-
- currentFile = imageFile;
-
- BufferedImage newBufferedImage;
- try {
- newBufferedImage = ImageUtil.read(imageFile);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- pixelFrame.notify("Could not read chosen file: " + imageFile.getAbsolutePath());
- return;
- }
-
- currentDisplayImageIcon = ImageUtil.resizeIfLengthExceeded(
- ImageUtil.toImageIcon(newBufferedImage), previewImageMaxLen);
- previewLabel.setIcon(currentDisplayImageIcon);
-
- refreshPreviewLabelSize();
- repaintPreviewLabelAndFrame();
- }
-
- /**
- * Refreshes the size of the preview label based on the current icon.
- */
- @ForReadability
- private static void refreshPreviewLabelSize() {
- ImageIcon previewIcon = (ImageIcon) previewLabel.getIcon();
- if (previewIcon == null) {
- previewLabel.setSize(previewImageMaxLen, previewImageMaxLen);
- } else {
- previewLabel.setSize(previewIcon.getIconWidth(), previewIcon.getIconHeight());
- }
- }
-
- /**
- * Revalidates and repaints the previewLabel and pixelFrame.
- */
- @ForReadability
- private static void repaintPreviewLabelAndFrame() {
- previewLabel.revalidate();
- previewLabel.repaint();
-
- pixelFrame.revalidate();
- pixelFrame.repaint();
- }
-}
diff --git a/src/main/java/cyder/widgets/MinecraftWidget.java b/src/main/java/cyder/widgets/MinecraftWidget.java
deleted file mode 100644
index d3a155044..000000000
--- a/src/main/java/cyder/widgets/MinecraftWidget.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.network.NetworkUtil;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.TitlePosition;
-import cyder.user.UserDataManager;
-import cyder.user.data.MappedExecutable;
-import cyder.utils.StaticUtil;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.io.File;
-
-/**
- * A widget emulating the Minecraft front page.
- */
-@Vanilla
-@CyderAuthor
-public final class MinecraftWidget {
- /**
- * The minecraft frame.
- */
- private static CyderFrame minecraftFrame;
-
- /**
- * The minecraft.net link that redirects to the hamburger icon's result.
- */
- public static final String MINECRAFT_HAMBURGER = "https://minecraft.net/en-us/?ref=m";
-
- /**
- * The minecraft.net link that redirects to the store icon's result.
- */
- public static final String MINECRAFT_CHEST = "https://minecraft.net/en-us/store/?ref=m";
-
- /**
- * The minecraft.net link that redirects to the realm icon's result.
- */
- public static final String MINECRAFT_REALMS = "https://minecraft.net/en-us/realms/?ref=m";
-
- /**
- * The minecraft.net link that redirects to the block icon's result.
- */
- public static final String MINECRAFT_BLOCK = "https://my.minecraft.net/en-us/store/minecraft/";
-
- /**
- * The block image icon.
- */
- private static final ImageIcon BLOCK = new ImageIcon(StaticUtil.getStaticPath("Block.png"));
-
- /**
- * The block enter animation.
- */
- private static final ImageIcon BLOCK_ENTER = new ImageIcon(StaticUtil.getStaticPath("BlockEnter.gif"));
-
- /**
- * The block exit animation.
- */
- private static final ImageIcon BLOCK_EXIT = new ImageIcon(StaticUtil.getStaticPath("BlockExit.gif"));
-
- /**
- * The realms icon.
- */
- private static final ImageIcon REALMS = new ImageIcon(StaticUtil.getStaticPath("Realms.png"));
-
- /**
- * The realms enter animation.
- */
- private static final ImageIcon REALMS_ENTER = new ImageIcon(StaticUtil.getStaticPath("RealmsEnter.gif"));
-
- /**
- * The realms exit animation.
- */
- private static final ImageIcon REALMS_EXIT = new ImageIcon(StaticUtil.getStaticPath("RealmsExit.gif"));
-
- /**
- * The chest icon.
- */
- private static final ImageIcon CHEST = new ImageIcon(StaticUtil.getStaticPath("Chest.png"));
-
- /**
- * The chest enter animation.
- */
- private static final ImageIcon CHEST_ENTER = new ImageIcon(StaticUtil.getStaticPath("ChestEnter.gif"));
-
- /**
- * The chest exit animation.
- */
- private static final ImageIcon CHEST_EXIT = new ImageIcon(StaticUtil.getStaticPath("ChestExit.gif"));
-
- /**
- * The hamburger icon.
- */
- private static final ImageIcon HAMBURGER = new ImageIcon(StaticUtil.getStaticPath("Hamburger.png"));
- /**
- * The hamburger enter animation.
- */
- private static final ImageIcon HAMBURGER_ENTER = new ImageIcon(
- StaticUtil.getStaticPath("HamburgerEnter.gif"));
-
- /**
- * The hamburger exit animation.
- */
- private static final ImageIcon HAMBURGER_EXIT = new ImageIcon(
- StaticUtil.getStaticPath("HamburgerExit.gif"));
-
- /**
- * The title of the widget frame.
- */
- private static final String FRAME_TITLE = "Minecraft Widget";
-
- /**
- * The width of the widget frame.
- */
- private static final int FRAME_WIDTH = 1263;
-
- /**
- * The height of the image frame.
- */
- private static final int FRAME_HEIGHT = 160;
-
- /**
- * Names of mapped exes which may reference a Minecraft executable.
- */
- private static final ImmutableList MINECRAFT_NAMES = ImmutableList.of(
- "Minecraft",
- "Lunar",
- "Badlion",
- "Optifine",
- "ATLauncher",
- "Technic",
- "Forge"
- );
-
- /**
- * The background of the frame.
- */
- private static final ImageIcon background = new ImageIcon(StaticUtil.getStaticPath("Minecraft.png"));
-
- /**
- * Suppress default constructor.
- */
- private MinecraftWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Widget(triggers = "minecraft", description = "A minecraft widget that copies from the Mojang home page")
- public static void showGui() {
- UiUtil.closeIfOpen(minecraftFrame);
- minecraftFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setBackgroundIcon(background)
- .build();
- minecraftFrame.setTitlePosition(TitlePosition.CENTER);
- minecraftFrame.setTitle(FRAME_TITLE);
-
- JLabel blockLabel = new JLabel(BLOCK);
- blockLabel.addMouseListener(generateMouseListener(blockLabel, MINECRAFT_BLOCK,
- BLOCK_ENTER, BLOCK_EXIT));
- blockLabel.setBounds(83, 46, 50, 45);
- minecraftFrame.getContentPane().add(blockLabel);
-
- JLabel realmsLabel = new JLabel(REALMS);
- realmsLabel.addMouseListener(generateMouseListener(realmsLabel, MINECRAFT_REALMS,
- REALMS_ENTER, REALMS_EXIT));
- realmsLabel.setBounds(196, 51, 70, 45);
- minecraftFrame.getContentPane().add(realmsLabel);
-
- JLabel chestLabel = new JLabel(CHEST);
- chestLabel.addMouseListener(generateMouseListener(chestLabel, MINECRAFT_CHEST,
- CHEST_ENTER, CHEST_EXIT));
- chestLabel.setBounds(1009, 44, 60, 50);
- minecraftFrame.getContentPane().add(chestLabel);
-
- JLabel hamLabel = new JLabel(HAMBURGER);
- hamLabel.addMouseListener(generateMouseListener(hamLabel, MINECRAFT_HAMBURGER,
- HAMBURGER_ENTER, HAMBURGER_EXIT));
- hamLabel.setBounds(1135, 52, 42, 40);
- minecraftFrame.getContentPane().add(hamLabel);
-
- int x = (UiUtil.getDefaultMonitorWidth() - FRAME_WIDTH) / 2;
- int y = UiUtil.getDefaultMonitorHeight() - FRAME_HEIGHT - UiUtil.getWindowsTaskbarHeight() / 2;
- minecraftFrame.finalizeAndShow(new Point(x, y));
- minecraftFrame.setIconImage(BLOCK.getImage());
-
- checkMappedExes();
- }
-
- /**
- * Generates a mouse adapter for a minecraft gif label.
- *
- * @param label the label
- * @param url the url to open on click
- * @param enterGif the enter gif
- * @param exitGif the exit gif
- * @return the mouse listener
- */
- @ForReadability
- private static MouseListener generateMouseListener(JLabel label, String url,
- ImageIcon enterGif, ImageIcon exitGif) {
- Preconditions.checkNotNull(label);
- Preconditions.checkNotNull(url);
- Preconditions.checkArgument(!url.isEmpty());
- Preconditions.checkNotNull(enterGif);
- Preconditions.checkNotNull(exitGif);
-
- return new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- NetworkUtil.openUrl(url);
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- enterGif.getImage().flush();
- label.setIcon(enterGif);
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- exitGif.getImage().flush();
- label.setIcon(exitGif);
- }
- };
- }
-
- /**
- * Checks the current user's mapped executables to determine if any might reference a Minecraft launcher.
- */
- private static void checkMappedExes() {
- UserDataManager.INSTANCE.getMappedExecutables().getExecutables()
- .stream().filter(MinecraftWidget::mappedExeReferencesPossibleMinecraftLauncher)
- .findFirst().ifPresent(exe -> FileUtil.openResourceUsingNativeProgram(exe.getFilepath()));
- }
-
- /**
- * Returns whether the provided mapped executable likely references a Minecraft launcher.
- *
- * @param mappedExecutable the mapped executable
- * @return whether the provided mapped executable likely references a Minecraft launcher
- */
- private static boolean mappedExeReferencesPossibleMinecraftLauncher(MappedExecutable mappedExecutable) {
- Preconditions.checkNotNull(mappedExecutable);
-
- File refFile = new File(mappedExecutable.getFilepath());
- if (refFile.exists() && refFile.isFile()) {
- return StringUtil.in(FileUtil.getFilename(refFile), true, MINECRAFT_NAMES);
- }
-
- return false;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/cyder/widgets/NotesWidget.java b/src/main/java/cyder/widgets/NotesWidget.java
deleted file mode 100644
index 5f86be2f6..000000000
--- a/src/main/java/cyder/widgets/NotesWidget.java
+++ /dev/null
@@ -1,873 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.getter.GetConfirmationBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.layouts.CyderGridLayout;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.threads.CyderThreadRunner;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderCaret;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.list.CyderScrollList;
-import cyder.ui.pane.CyderPanel;
-import cyder.ui.pane.CyderScrollPane;
-import cyder.user.UserDataManager;
-import cyder.user.UserFile;
-import cyder.utils.OsUtil;
-
-import javax.swing.*;
-import javax.swing.border.Border;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * A note taking widget.
- */
-@Vanilla
-@CyderAuthor
-public final class NotesWidget {
- /**
- * The notes selection and creation list frame.
- */
- private static CyderFrame noteFrame;
-
- /**
- * The default frame width.
- */
- private static final int defaultFrameWidth = 600;
-
- /**
- * The default frame height.
- */
- private static final int defaultFrameHeight = 680;
-
- /**
- * The padding between the frame and the note files scrolls.
- */
- private static final int noteListScrollPadding = 25;
-
- /**
- * The length of the note files list scroll.
- */
- private static final int noteListScrollLength = defaultFrameWidth - 2 * noteListScrollPadding;
-
- /**
- * The padding between the frame and the note contents scrolls.
- */
- private static final int noteScrollPadding = 50;
-
- /**
- * The notes list scroll.
- */
- private static CyderScrollList notesScrollList;
-
- /**
- * The length of the notes JTextArea.
- */
- private static final int noteAreaLength = defaultFrameWidth - 2 * noteScrollPadding;
-
- /**
- * The partitioned layout for the notes scroll view.
- */
- private static CyderPartitionedLayout framePartitionedLayout;
-
- /**
- * The current frame view.
- */
- private static View currentView;
-
- /**
- * The button size of most buttons.
- */
- private static final Dimension buttonSize = new Dimension(160, 40);
-
- /**
- * The new note contents area.
- */
- private static JTextPane newNoteArea;
-
- /**
- * The new note name field.
- */
- private static CyderTextField newNoteNameField;
-
- /**
- * The add button text.
- */
- private static final String ADD = "Add";
-
- /**
- * The open button text.
- */
- private static final String OPEN = "Open";
-
- /**
- * The delete button text.
- */
- private static final String DELETE = "Delete";
-
- /**
- * The possible widget views.
- */
- private enum View {
- LIST,
- ADD,
- EDIT,
- }
-
- /**
- * The description for this widget.
- */
- private static final String description = "A note taking widget that can save and display multiple notes";
-
- /**
- * The font for the note name fields.
- */
- private static final Font noteNameFieldFont = new Font("Agency FB", Font.BOLD, 26);
-
- /**
- * The border for the note name fields.
- */
- private static final Border noteNameFieldBorder
- = BorderFactory.createMatteBorder(0, 0, 4, 0, CyderColors.navy);
-
- /**
- * The height of the note scrolls.
- */
- private static final int noteScrollHeight = noteAreaLength - 2 * noteListScrollPadding;
-
- /**
- * The back button text.
- */
- private static final String BACK = "Back";
-
- /**
- * The create button text.
- */
- private static final String CREATE = "Create";
-
- /**
- * The list of currently read notes from the user's notes directory.
- */
- private static final ArrayList notesList = new ArrayList<>();
-
- /**
- * The exit text.
- */
- private static final String EXIT = "Exit";
-
- /**
- * The stay text (I told you that I never would).
- */
- private static final String STAY = "Stay";
-
- /**
- * The name of the thread which waits for a save confirmation.
- */
- private static final String NOTE_EDITOR_EXIT_CONFIRMATION_WAITER_THREAD_NAME = "Note editor exit confirmation";
-
- /**
- * The add note button text.
- */
- private static final String ADD_NOTE = "Add note";
-
- /**
- * The edit note name field.
- */
- private static CyderTextField editNoteNameField;
-
- /**
- * The edit note contents area.
- */
- private static JTextPane noteEditArea;
-
- /**
- * The save button text.
- */
- private static final String SAVE = "Save";
-
- /**
- * The currently being edited note file.
- */
- private static File currentNoteFile;
-
- /**
- * The confirmation message to display when a user attempts to close the frame when there are pending changes.
- */
- private static final String closingConfirmationMessage = "You have unsaved changes, are you sure you wish to exit?";
-
- /**
- * Whether the current note has unsaved changes.
- */
- private static boolean unsavedChanges = false;
-
- /**
- * Whether a new note being added has information that would be lost.
- */
- private static boolean newNoteContent = false;
-
- /**
- * The notification text to display when a note is saved.
- */
- private static final String SAVED_NOTE = "Saved note";
-
- /**
- * The last time the current note was saved at.
- */
- private static final AtomicLong lastSave = new AtomicLong();
-
- /**
- * The timeout between allowable note save actions.
- */
- private static final int SAVE_BUTTON_TIMEOUT = 500;
-
- /**
- * The border length for the note scroll.
- */
- private static final int noteScrollBorderLen = 5;
-
- /**
- * The padding partition for primary view components.
- */
- private static final int viewPartitionPadding = 2;
-
- /**
- * The length of the note content scroll view.
- */
- private static final int noteContentScrollLength = noteAreaLength - 2 * noteScrollBorderLen;
-
- /**
- * The encoding format for note files.
- */
- private static final Charset noteFileEncoding = StandardCharsets.UTF_8;
-
- /**
- * Suppress default constructor.
- */
- private NotesWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Widget(triggers = {"note", "notes"}, description = description)
- public static void showGui() {
- Preconditions.checkNotNull(Console.INSTANCE.getUuid());
- UiUtil.closeIfOpen(noteFrame);
- noteFrame = new CyderFrame.Builder()
- .setWidth(defaultFrameWidth)
- .setHeight(defaultFrameHeight)
- .build();
- setupView(View.LIST);
- noteFrame.finalizeAndShow();
- }
-
- /**
- * Sets up the frame for the provided view.
- *
- * @param view the view
- */
- private static void setupView(View view) {
- Preconditions.checkNotNull(view);
- currentView = view;
-
- switch (view) {
- case LIST -> setupListView();
- case ADD -> setupAddView();
- case EDIT -> setupEditView();
- }
- }
-
- /**
- * Sets up and shows the notes list view.
- */
- private static void setupListView() {
- refreshNotesList();
- resetUnsavedContentVars();
-
- currentNoteFile = null;
-
- framePartitionedLayout = new CyderPartitionedLayout();
-
- JLabel notesLabel = regenerateAndGetNotesScrollLabel();
-
- CyderGridLayout buttonGridlayout = new CyderGridLayout(3, 1);
-
- CyderButton addButton = new CyderButton(ADD);
- addButton.setSize(buttonSize);
- addButton.addActionListener(e -> setupView(View.ADD));
- buttonGridlayout.addComponent(addButton);
-
- CyderButton openButton = new CyderButton(OPEN);
- openButton.setSize(buttonSize);
- openButton.addActionListener(e -> openButtonAction());
- buttonGridlayout.addComponent(openButton);
-
- CyderButton deleteButton = new CyderButton(DELETE);
- deleteButton.setSize(buttonSize);
- deleteButton.addActionListener(e -> deleteButtonAction());
- buttonGridlayout.addComponent(deleteButton);
-
- CyderPanel buttonPanel = new CyderPanel(buttonGridlayout);
- buttonPanel.setSize(notesLabel.getWidth(), 50);
-
- framePartitionedLayout.spacer(viewPartitionPadding);
- framePartitionedLayout.addComponentMaintainSize(notesLabel, CyderPartitionedLayout.PartitionAlignment.TOP);
- framePartitionedLayout.spacer(viewPartitionPadding);
- framePartitionedLayout.addComponent(buttonPanel);
- framePartitionedLayout.spacer(viewPartitionPadding);
-
- noteFrame.setCyderLayout(framePartitionedLayout);
- noteFrame.repaint();
- revalidateFrameTitle();
- }
-
- /**
- * Sets up and shows the add note view.
- */
- private static void setupAddView() {
- noteFrame.removeCyderLayoutPanel();
- noteFrame.repaint();
-
- newNoteNameField = new CyderTextField();
- newNoteNameField.addKeyListener(getAddNoteKeyListener());
- newNoteNameField.setFont(noteNameFieldFont);
- newNoteNameField.setForeground(CyderColors.navy);
- newNoteNameField.setCaret(new CyderCaret(CyderColors.navy));
- newNoteNameField.setBackground(CyderColors.vanilla);
- newNoteNameField.setSize(300, 40);
- newNoteNameField.setToolTipText("Note name");
- newNoteNameField.setBorder(noteNameFieldBorder);
-
- newNoteArea = new JTextPane();
- newNoteArea.addKeyListener(getAddNoteKeyListener());
- newNoteArea.setSize(noteAreaLength, noteScrollHeight);
- newNoteArea.setBackground(CyderColors.vanilla);
- newNoteArea.setFocusable(true);
- newNoteArea.setEditable(true);
- newNoteArea.setSelectionColor(CyderColors.selectionColor);
- newNoteArea.setFont(Console.INSTANCE.generateUserFont());
- newNoteArea.setForeground(CyderColors.navy);
- newNoteArea.setCaret(new CyderCaret(CyderColors.navy));
- newNoteArea.setCaretColor(newNoteArea.getForeground());
-
- CyderScrollPane noteScroll = new CyderScrollPane(newNoteArea,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
- noteScroll.setThumbColor(CyderColors.regularPink);
- noteScroll.setBorder(new LineBorder(CyderColors.navy, 5));
- noteScroll.setSize(noteContentScrollLength, noteContentScrollLength);
- noteScroll.getViewport().setOpaque(false);
- noteScroll.setOpaque(false);
- noteScroll.setBorder(null);
- newNoteArea.setAutoscrolls(true);
-
- JLabel noteScrollLabel = new JLabel();
- noteScrollLabel.setSize(noteAreaLength, noteAreaLength);
- noteScrollLabel.setBorder(new LineBorder(CyderColors.navy, noteScrollBorderLen));
- noteScroll.setLocation(noteScrollBorderLen, noteScrollBorderLen);
- noteScrollLabel.add(noteScroll);
-
- CyderButton backButton = new CyderButton(BACK);
- backButton.setSize(buttonSize);
- backButton.addActionListener(e -> setupView(View.LIST));
-
- CyderButton createButton = new CyderButton(CREATE);
- createButton.setSize(buttonSize);
- createButton.addActionListener(e -> createNoteAction());
-
- CyderGridLayout buttonGridLayout = new CyderGridLayout(2, 1);
- buttonGridLayout.addComponent(createButton);
- buttonGridLayout.addComponent(backButton);
- CyderPanel buttonGridPanel = new CyderPanel(buttonGridLayout);
- buttonGridPanel.setSize(400, 50);
-
- CyderPartitionedLayout addNoteLayout = new CyderPartitionedLayout();
- addNoteLayout.spacer(viewPartitionPadding);
- addNoteLayout.addComponentMaintainSize(newNoteNameField);
- addNoteLayout.spacer(viewPartitionPadding);
- addNoteLayout.addComponentMaintainSize(noteScrollLabel);
- addNoteLayout.spacer(viewPartitionPadding);
- addNoteLayout.addComponentMaintainSize(buttonGridPanel);
- addNoteLayout.spacer(viewPartitionPadding);
-
- noteFrame.setCyderLayout(addNoteLayout);
- revalidateFrameTitle();
- noteFrame.repaint();
- }
-
- /**
- * Returns a key listener for the add note name field and content area.
- *
- * @return a key listener for the add note name field and content area
- */
- private static KeyListener getAddNoteKeyListener() {
- return new KeyAdapter() {
- @Override
- public void keyReleased(KeyEvent e) {
- super.keyReleased(e);
- refreshNewNoteChanges();
- }
- };
- }
-
- /**
- * The actions to invoke when the open button is pressed.
- */
- private static void openButtonAction() {
- Optional optionalFile = notesScrollList.getSelectedElement();
- if (optionalFile.isEmpty()) return;
- String noteName = optionalFile.get();
-
- notesList.stream().filter(noteFile -> noteFile.getName().equals(noteName))
- .forEach(noteFile -> currentNoteFile = noteFile);
-
- setupView(View.EDIT);
- }
-
- /**
- * The actions to invoke when the create new note button is clicked in the add note view.
- */
- private static void createNoteAction() {
- String noteName = newNoteNameField.getTrimmedText();
- if (noteName.isEmpty()) {
- noteFrame.notify("Missing name for note");
- return;
- }
-
- if (StringUtil.in(noteName, true, getCurrentNoteFileNames())) {
- noteFrame.notify("Note name already in use");
- return;
- }
-
- if (noteName.toLowerCase().endsWith(Extension.TXT.getExtension())) {
- noteName = noteName.substring(0, noteName.length() - Extension.TXT.getExtension().length());
- }
-
- String requestedName = noteName + Extension.TXT.getExtension();
-
- if (!FileUtil.isValidFilename(requestedName)) {
- noteFrame.notify("Invalid filename");
- return;
- }
-
- File createFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.NOTES.getName(), requestedName);
- if (!OsUtil.createFile(createFile, true)) {
- noteFrame.notify("Could not create file: "
- + CyderStrings.quote + requestedName + CyderStrings.quote);
- return;
- }
-
- String contents = newNoteArea.getText();
- try (BufferedWriter write = new BufferedWriter(new FileWriter(createFile))) {
- write.write(contents);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- setupView(View.LIST);
- noteFrame.notify("Added note file: "
- + CyderStrings.quote + requestedName + CyderStrings.quote);
- }
-
- /**
- * Reads and returns the contents of the current note file.
- *
- * @return the contents of the current note file
- */
- private static String getCurrentNoteContents() {
- try {
- byte[] encoded = Files.readAllBytes(Paths.get(currentNoteFile.getAbsolutePath()));
- return new String(encoded, noteFileEncoding);
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- throw new IllegalStateException("Could not read contents of current note file");
- }
-
- /**
- * Sets up and shows the edit note view.
- */
- private static void setupEditView() {
- Preconditions.checkNotNull(currentNoteFile);
-
- noteFrame.removeCyderLayoutPanel();
- noteFrame.repaint();
-
- editNoteNameField = new CyderTextField();
- editNoteNameField.addKeyListener(getEditNoteKeyListener());
- editNoteNameField.setFont(noteNameFieldFont);
- editNoteNameField.setForeground(CyderColors.navy);
- editNoteNameField.setCaret(new CyderCaret(CyderColors.navy));
- editNoteNameField.setBackground(CyderColors.vanilla);
- editNoteNameField.setSize(300, 40);
- editNoteNameField.setToolTipText("Note name");
- editNoteNameField.setBorder(noteNameFieldBorder);
- editNoteNameField.setText(FileUtil.getFilename(currentNoteFile));
-
- noteEditArea = new JTextPane();
- noteEditArea.addKeyListener(getEditNoteKeyListener());
- noteEditArea.setText(getCurrentNoteContents());
- noteEditArea.setSize(noteAreaLength, noteScrollHeight);
- noteEditArea.setBackground(CyderColors.vanilla);
- noteEditArea.setFocusable(true);
- noteEditArea.setEditable(true);
- noteEditArea.setSelectionColor(CyderColors.selectionColor);
- noteEditArea.setFont(Console.INSTANCE.generateUserFont());
- noteEditArea.setForeground(CyderColors.navy);
- noteEditArea.setCaret(new CyderCaret(CyderColors.navy));
- noteEditArea.setCaretColor(noteEditArea.getForeground());
- noteEditArea.addKeyListener(saveNoteEditAreaKeyListener);
-
- CyderScrollPane noteScroll = new CyderScrollPane(noteEditArea,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
- noteScroll.setThumbColor(CyderColors.regularPink);
- noteScroll.setSize(noteContentScrollLength, noteContentScrollLength);
- noteScroll.getViewport().setOpaque(false);
- noteScroll.setOpaque(false);
- noteScroll.setBorder(null);
- noteEditArea.setAutoscrolls(true);
-
- JLabel noteScrollLabel = new JLabel();
- noteScrollLabel.setSize(noteAreaLength, noteAreaLength);
- noteScrollLabel.setBorder(new LineBorder(CyderColors.navy, noteScrollBorderLen));
- noteScroll.setLocation(noteScrollBorderLen, noteScrollBorderLen);
- noteScrollLabel.add(noteScroll);
-
- CyderButton saveButton = new CyderButton(SAVE);
- saveButton.setSize(buttonSize);
- saveButton.addActionListener(e -> editNoteSaveButtonAction());
- lastSave.set(System.currentTimeMillis());
-
- CyderButton backButton = new CyderButton(BACK);
- backButton.setSize(buttonSize);
- backButton.addActionListener(e -> editBackButtonAction());
-
- CyderGridLayout buttonGridLayout = new CyderGridLayout(2, 1);
- buttonGridLayout.addComponent(saveButton);
- buttonGridLayout.addComponent(backButton);
- CyderPanel buttonGridPanel = new CyderPanel(buttonGridLayout);
- buttonGridPanel.setSize(400, 50);
-
- CyderPartitionedLayout editNoteLayout = new CyderPartitionedLayout();
- editNoteLayout.spacer(viewPartitionPadding);
- editNoteLayout.addComponentMaintainSize(editNoteNameField);
- editNoteLayout.spacer(viewPartitionPadding);
- editNoteLayout.addComponentMaintainSize(noteScrollLabel);
- editNoteLayout.spacer(viewPartitionPadding);
- editNoteLayout.addComponentMaintainSize(buttonGridPanel);
- editNoteLayout.spacer(viewPartitionPadding);
-
- refreshUnsavedChanges();
- noteFrame.setCyderLayout(editNoteLayout);
- revalidateFrameTitle();
-
- noteFrame.repaint();
- }
-
- /**
- * The key listener for saving the edited note contents to the note file when ctrl + s is performed.
- */
- private static final KeyListener saveNoteEditAreaKeyListener = new KeyAdapter() {
- @Override
- public void keyPressed(KeyEvent e) {
- if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_S) {
- editNoteSaveButtonAction();
- }
- }
- };
-
- /**
- * Returns a key listener for the edit note name field and content area.
- *
- * @return a key listener for the edit note name field and content area
- */
- private static KeyListener getEditNoteKeyListener() {
- return new KeyAdapter() {
- @Override
- public void keyReleased(KeyEvent e) {
- super.keyReleased(e);
- refreshUnsavedChanges();
- }
- };
- }
-
- /**
- * The actions to invoke when the save button on the edit note view is pressed.
- */
- private static void editNoteSaveButtonAction() {
- if (System.currentTimeMillis() < lastSave.get() + SAVE_BUTTON_TIMEOUT) return;
- lastSave.set(System.currentTimeMillis());
-
- String noteNameFieldText = editNoteNameField.getTrimmedText();
- if (noteNameFieldText.isEmpty()) {
- noteFrame.notify("Missing name for note");
- return;
- }
-
- if (StringUtil.in(noteNameFieldText, true, getCurrentNoteFileNames())
- && !FileUtil.getFilename(currentNoteFile).equals(noteNameFieldText)) {
- noteFrame.notify("Note name already in use");
- return;
- }
-
- String newFilename = noteNameFieldText + Extension.TXT.getExtension();
- if (!FileUtil.isValidFilename(newFilename)) {
- noteFrame.notify("Invalid filename: " + CyderStrings.quote + newFilename + CyderStrings.quote);
- return;
- }
-
- if (!OsUtil.deleteFile(currentNoteFile)) {
- noteFrame.notify("Failed to update note contents");
- return;
- }
-
- File newFile = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.NOTES.getName(), newFilename);
- if (!OsUtil.createFile(newFile, true)) {
- noteFrame.notify("Failed to update note contents");
- return;
- }
-
- currentNoteFile = newFile;
-
- String contents = noteEditArea.getText();
- saveToCurrentNote(contents);
- }
-
- /**
- * Saves the provided contents to the current note file.
- *
- * @param contents the contents to save
- */
- private static void saveToCurrentNote(String contents) {
- Preconditions.checkNotNull(contents);
-
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(currentNoteFile))) {
- writer.write(contents);
- noteFrame.notify(SAVED_NOTE);
- setUnsavedChanges(false);
- } catch (Exception exception) {
- ExceptionHandler.handle(exception);
- }
- }
-
- /**
- * The action to invoke when the back button on the edit note view is pressed.
- */
- private static void editBackButtonAction() {
- CyderThreadRunner.submit(() -> {
- String currentName = editNoteNameField.getTrimmedText();
- String currentContents = noteEditArea.getText();
-
- StringBuilder pendingChangesBuilder = new StringBuilder();
- String currentlySavedName = FileUtil.getFilename(currentNoteFile);
- if (!currentName.equals(currentlySavedName)) {
- pendingChangesBuilder.append("Note name pending changes");
- }
-
- String currentSavedContents = getCurrentNoteContents();
- if (!currentContents.equals(currentSavedContents)) {
- if (!pendingChangesBuilder.isEmpty()) {
- pendingChangesBuilder.append(", ");
- }
- pendingChangesBuilder.append("Note contents pending changes");
- }
-
- boolean pendingChanges = !pendingChangesBuilder.isEmpty();
- if (pendingChanges) {
- GetConfirmationBuilder builder
- = new GetConfirmationBuilder("Pending changes", pendingChangesBuilder.toString())
- .setRelativeTo(noteFrame)
- .setDisableRelativeTo(true)
- .setYesButtonText(EXIT)
- .setNoButtonText(STAY);
- boolean shouldGoBack = GetterUtil.getInstance().getConfirmation(builder);
- if (!shouldGoBack) return;
- }
-
- setupView(View.LIST);
- }, NOTE_EDITOR_EXIT_CONFIRMATION_WAITER_THREAD_NAME);
- }
-
- /**
- * Revalidates the frame title based on the current view.
- */
- private static void revalidateFrameTitle() {
- switch (currentView) {
- case LIST -> {
- String name = UserDataManager.INSTANCE.getUsername();
- noteFrame.setTitle(name + StringUtil.getApostropheSuffix(name) + " notes");
- }
- case ADD -> noteFrame.setTitle(ADD_NOTE);
- case EDIT -> {
- String name = currentNoteFile == null ? "" : FileUtil.getFilename(currentNoteFile);
- noteFrame.setTitle("Editing note: " + name);
- }
- }
- }
-
- /**
- * The actions to invoke when the delete button is pressed.
- */
- private static void deleteButtonAction() {
- Optional selectedElement = notesScrollList.getSelectedElement();
- if (selectedElement.isEmpty()) return;
-
- notesList.stream().filter(noteFile ->
- noteFile.getName().equals(selectedElement.get())).forEach(OsUtil::deleteFile);
- refreshNotesList();
- notesScrollList.removeSelectedElement();
-
- JLabel notesLabel = regenerateAndGetNotesScrollLabel();
- framePartitionedLayout.setComponent(notesLabel, 1);
- noteFrame.repaint();
- }
-
- /**
- * Regenerates the notes scroll list and the JLabel and returns the generated component.
- *
- * @return the generated component
- */
- @ForReadability
- private static JLabel regenerateAndGetNotesScrollLabel() {
- notesScrollList = new CyderScrollList(noteListScrollLength, noteListScrollLength,
- CyderScrollList.SelectionPolicy.SINGLE);
- notesList.forEach(noteFile -> notesScrollList.addElementWithDoubleClickAction(noteFile.getName(), () -> {
- currentNoteFile = noteFile;
- setupView(View.EDIT);
- }));
- JLabel notesLabel = notesScrollList.generateScrollList();
- notesLabel.setSize(noteListScrollLength, noteListScrollLength);
- return notesLabel;
- }
-
- /**
- * Refreshes the contents of the notes list.
- */
- private static void refreshNotesList() throws IllegalStateException {
- File dir = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.NOTES.getName());
- if (!dir.exists()) return;
-
- notesList.clear();
-
- File[] noteFiles = dir.listFiles();
- if (noteFiles == null) return;
-
- Arrays.stream(noteFiles).filter(noteFile ->
- FileUtil.getExtension(noteFile).equals(Extension.TXT.getExtension())).forEach(notesList::add);
- }
-
- /**
- * Refreshes the state of {@link #unsavedChanges}.
- */
- private static void refreshUnsavedChanges() {
- boolean filenameDifferent = !FileUtil.getFilename(currentNoteFile).equals(editNoteNameField.getText());
- boolean contentsDifferent = !getCurrentNoteContents().equals(noteEditArea.getText());
- setUnsavedChanges(contentsDifferent || filenameDifferent);
- }
-
- /**
- * Refreshes the state of {@link #newNoteContent}.
- */
- private static void refreshNewNoteChanges() {
- boolean filenameContents = !newNoteNameField.getTrimmedText().isEmpty();
- boolean contents = !newNoteArea.getText().isEmpty();
- setNewNoteContent(filenameContents || contents);
- }
-
- /**
- * Sets whether there are unsaved changes in the current note or note being created and thus
- * whether a closing confirmation should be displayed if the frame is attempted to be disposed.
- *
- * @param newUnsavedChangesValue whether there are unsaved changes.
- */
- private static void setUnsavedChanges(boolean newUnsavedChangesValue) {
- if (unsavedChanges == newUnsavedChangesValue) return;
- unsavedChanges = newUnsavedChangesValue;
- if (newNoteContent) return;
-
- if (newUnsavedChangesValue) {
- noteFrame.setClosingConfirmation(closingConfirmationMessage);
- } else {
- noteFrame.removeClosingConfirmation();
- }
- }
-
- /**
- * Sets whether there is an unsaved note with contents that would be lost if the frame was disposed
- * and thus whether a closing confirmation should be displayed if the frame is attempted to be disposed.
- *
- * @param newNoteContainsContent whether there is a new note present with unsaved changes
- */
- private static void setNewNoteContent(boolean newNoteContainsContent) {
- if (newNoteContent == newNoteContainsContent) return;
- newNoteContent = newNoteContainsContent;
- if (unsavedChanges) return;
-
- if (newNoteContainsContent) {
- noteFrame.setClosingConfirmation(closingConfirmationMessage);
- } else {
- noteFrame.removeClosingConfirmation();
- }
- }
-
- /**
- * Resets the states of {@link #unsavedChanges} and {@link #newNoteContent}
- * and removes the closing confirmation from the note frame if present.
- */
- private static void resetUnsavedContentVars() {
- unsavedChanges = false;
- newNoteContent = false;
-
- noteFrame.removeClosingConfirmation();
- }
-
- private static ImmutableList getCurrentNoteFileNames() {
- ArrayList ret = new ArrayList<>();
-
- File userNotesDir = Dynamic.buildDynamic(Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.NOTES.getName());
- if (userNotesDir.exists()) {
- File[] noteFiles = userNotesDir.listFiles();
- if (noteFiles != null && noteFiles.length > 0) {
- Arrays.stream(noteFiles).forEach(noteFile -> ret.add(FileUtil.getFilename(noteFile)));
- }
- }
-
- return ImmutableList.copyOf(ret);
- }
-}
diff --git a/src/main/java/cyder/widgets/PaintWidget.java b/src/main/java/cyder/widgets/PaintWidget.java
deleted file mode 100644
index 9e77ed948..000000000
--- a/src/main/java/cyder/widgets/PaintWidget.java
+++ /dev/null
@@ -1,825 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.console.Console;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderIcons;
-import cyder.constants.CyderRegexPatterns;
-import cyder.enumerations.Dynamic;
-import cyder.enumerations.Extension;
-import cyder.exceptions.IllegalMethodException;
-import cyder.files.FileUtil;
-import cyder.getter.GetFileBuilder;
-import cyder.getter.GetInputBuilder;
-import cyder.getter.GetterUtil;
-import cyder.handlers.external.ImageViewer;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.layouts.CyderGridLayout;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderIconButton;
-import cyder.ui.drag.CyderDragLabel;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.frame.enumerations.FrameType;
-import cyder.ui.frame.notification.NotificationBuilder;
-import cyder.ui.grid.CyderGrid;
-import cyder.ui.grid.GridNode;
-import cyder.ui.label.CyderLabel;
-import cyder.ui.pane.CyderPanel;
-import cyder.ui.selection.CyderCheckbox;
-import cyder.ui.selection.CyderCheckboxGroup;
-import cyder.ui.slider.CyderSliderUi;
-import cyder.ui.slider.ThumbShape;
-import cyder.user.UserFile;
-import cyder.user.UserUtil;
-import cyder.utils.ColorUtil;
-import cyder.utils.ImageUtil;
-import cyder.utils.OsUtil;
-import cyder.utils.StaticUtil;
-
-import javax.imageio.ImageIO;
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Optional;
-
-/**
- * A painting widget, not currently intended to be able to edit/markup images.
- */
-@Vanilla
-@CyderAuthor
-public final class PaintWidget {
- /**
- * The length of the frame.
- */
- public static final int frameLength = 800;
-
- /**
- * The master painting frame.
- */
- private static CyderFrame paintFrame;
-
- /**
- * The painting grid.
- */
- private static CyderGrid cyderGrid;
-
- /**
- * The button for selecting a region.
- */
- private static CyderIconButton selectionTool;
-
- /**
- * The button for selecting a color.
- */
- private static CyderIconButton selectColor;
-
- /**
- * Suppress default constructor.
- */
- private PaintWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * ShowGUI method standard.
- */
- @Widget(triggers = {"paint", "draw"}, description = "A painting widget")
- public static void showGui() {
- UiUtil.closeIfOpen(paintFrame);
-
- paintFrame = new CyderFrame.Builder()
- .setWidth(frameLength)
- .setHeight(frameLength)
- .setTitle("Paint")
- .build();
- paintFrame.setBackground(CyderIcons.defaultBackgroundLarge);
- paintFrame.addPreCloseAction(() -> UiUtil.closeIfOpen(paintControlsFrame));
- paintFrame.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent e) {
- UiUtil.closeIfOpen(paintControlsFrame);
- }
-
- @Override
- public void windowClosed(WindowEvent e) {
- UiUtil.closeIfOpen(paintControlsFrame);
- }
- });
-
- cyderGrid = new CyderGrid(200, frameLength);
- cyderGrid.setBounds(0, CyderDragLabel.DEFAULT_HEIGHT - 5, frameLength, frameLength);
- paintFrame.getContentPane().add(cyderGrid);
- cyderGrid.setResizable(true);
- cyderGrid.setDrawGridLines(false);
- cyderGrid.installClickListener();
- cyderGrid.installDragListener();
- cyderGrid.setSmoothScrolling(true);
- cyderGrid.setDrawWidth(DEFAULT_BRUSH_WIDTH);
- cyderGrid.setNodeColor(currentPaintColor);
-
- paintFrame.setMenuButtonShown(true);
- paintFrame.addMenuItem("Export PNG", () -> CyderThreadRunner.submit(() -> {
- if (cyderGrid.getGridNodes().isEmpty()) {
- paintFrame.notify("Please place at least one node before saving");
- return;
- }
-
- String filename = FileUtil.constructUniqueName(new File("image" + Extension.PNG.getExtension()),
- OsUtil.buildFile(Dynamic.PATH, Dynamic.USERS.getFileName(),
- Console.INSTANCE.getUuid(), UserFile.FILES.getName()));
-
- Optional optionalFilename = GetterUtil.getInstance().getInput(
- new GetInputBuilder("Filename", "Enter the filename to save the image as")
- .setRelativeTo(paintFrame)
- .setInitialFieldText(filename)
- .setSubmitButtonText("Save Image"));
- if (optionalFilename.isEmpty()) return;
- filename = optionalFilename.get();
-
- if (!filename.endsWith(Extension.PNG.getExtension())) {
- filename += Extension.PNG.getExtension();
- }
-
- if (FileUtil.isValidFilename(filename)) {
- BufferedImage image = new BufferedImage(cyderGrid.getNodeDimensionLength(),
- cyderGrid.getNodeDimensionLength(), BufferedImage.TYPE_INT_ARGB);
-
- Graphics2D g2d = (Graphics2D) image.getGraphics();
-
- for (GridNode node : cyderGrid.getGridNodes()) {
- g2d.setColor(node.getColor());
- g2d.fillRect(node.getX(), node.getY(), 1, 1);
- }
-
- try {
- File referenceFile = UserUtil.createFileInUserSpace(filename);
- ImageIO.write(image, Extension.PNG.getExtensionWithoutPeriod(), referenceFile);
-
- paintFrame.notify(new NotificationBuilder(
- "Successfully saved grid as " + CyderStrings.quote + filename
- + CyderStrings.quote + " to your Files/ directory. Click me to view it")
- .setOnKillAction(() -> ImageViewer.getInstance(referenceFile).showGui()));
- } catch (Exception exception) {
- ExceptionHandler.handle(exception);
- paintFrame.notify("Could not save image at this time");
- }
- } else {
- paintFrame.notify("Sorry, but " + CyderStrings.quote
- + filename + CyderStrings.quote + " is not a valid filename");
- }
- }, "Paint Grid Exporter"));
- paintFrame.addMenuItem("Layer Image", () -> CyderThreadRunner.submit(() -> {
- try {
- Optional optionalFile = GetterUtil.getInstance().getFile(
- new GetFileBuilder("Layer Image").setRelativeTo(paintFrame));
- if (optionalFile.isEmpty()) return;
- File chosenImage = optionalFile.get();
-
- if (FileUtil.validateExtension(chosenImage, FileUtil.SUPPORTED_IMAGE_EXTENSIONS)) {
- // todo layer image logic
- } else {
- paintFrame.notify("Image type not supported");
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- paintFrame.notify("Could not add image at this time");
- }
- }, "Paint Grid Image Layerer"));
- paintFrame.addMenuItem("Pixelate", () -> CyderThreadRunner.submit(() -> {
- try {
- Optional optionalPixelSizeString = GetterUtil.getInstance().getInput(
- new GetInputBuilder("Pixelator", "Enter the pixel size")
- .setFieldHintText("Pixel size")
- .setRelativeTo(paintFrame)
- .setSubmitButtonText("Pixelate Grid")
- .setInitialFieldText(String.valueOf(1)));
- if (optionalPixelSizeString.isEmpty()) return;
- String pixelSizeString = optionalPixelSizeString.get();
-
- int pixelSize = Integer.parseInt(pixelSizeString);
- if (pixelSize == 1) return;
- // todo pixelate image
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- paintFrame.notify("Could not pixelate image at this time");
- }
- }, "Paint Grid Pixelator"));
- paintFrame.addMenuItem("Scale", () -> CyderThreadRunner.submit(() -> {
- try {
- Optional optionalDimension = GetterUtil.getInstance().getInput(
- new GetInputBuilder("Enter length", "Enter the canvas length")
- .setFieldHintText("Grid Length")
- .setRelativeTo(paintFrame)
- .setSubmitButtonText("Scale grid")
- .setInitialFieldText(String.valueOf(cyderGrid.getNodeDimensionLength())));
- if (optionalDimension.isEmpty()) return;
- String dimension = optionalDimension.get();
-
- int dimensionInt = Integer.parseInt(dimension);
-
- if (dimensionInt > 0) {
- // create reference image to resize
- BufferedImage referenceImage = new BufferedImage(cyderGrid.getNodeDimensionLength(),
- cyderGrid.getNodeDimensionLength(), BufferedImage.TYPE_INT_ARGB);
-
- Graphics2D g2d = (Graphics2D) referenceImage.getGraphics();
-
- for (GridNode node : cyderGrid.getGridNodes()) {
- g2d.setColor(node.getColor());
- g2d.fillRect(node.getX(), node.getY(), 1, 1);
- }
-
- double scaler = (double) dimensionInt / cyderGrid.getNodeDimensionLength();
- int len = (int) (scaler * referenceImage.getWidth());
-
- BufferedImage newStateImage = ImageUtil.resizeImage(
- referenceImage, BufferedImage.TYPE_INT_ARGB, len, len);
-
- cyderGrid.setNodeDimensionLength(len);
-
- ArrayList newState = new ArrayList<>();
-
- for (int x = 0 ; x < newStateImage.getWidth() ; x++) {
- for (int y = 0 ; y < newStateImage.getHeight() ; y++) {
- int color = newStateImage.getRGB(x, y);
-
- // if alpha is empty, don't copy over
- if (((color >> 24) & 0xFF) == 0)
- continue;
-
- newState.add(new GridNode(new Color(
- (color >> 16) & 0xFF,
- (color >> 8) & 0xFF,
- color & 0xFF), x, y));
- }
- }
-
- cyderGrid.setGridState(newState);
- } else {
- paintFrame.notify("Invalid dimensional length");
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- }, "Paint Grid Scaler"));
- paintFrame.addMenuItem("Controls", PaintWidget::installControlFrames);
-
- installControlFrames();
- }
-
- /**
- * Returns the aspect ratio of the provided buffered image.
- *
- * @param img the image to find the aspect ratio of
- * @return the aspect ratio of the provided buffered image
- */
- private static double getAspectRatio(BufferedImage img) {
- return ((double) img.getWidth() / (double) img.getHeight());
- }
-
- /**
- * The controls frame.
- */
- private static CyderFrame paintControlsFrame;
-
- /**
- * The list of recently used colors.
- */
- private static ArrayList recentColors;
-
- /**
- * The custom component with an overridden paint component.
- */
- private static JLabel recentColorsBlock;
-
- /**
- * The current color.
- */
- private static Color currentPaintColor = CyderColors.regularPink;
-
- /**
- * The hex field that displays the current color value.
- */
- private static CyderTextField colorHexField;
-
- /**
- * The add nodes checkbox.
- */
- private static CyderCheckbox addNodesCheckbox;
-
- /**
- * Opens the paint controls frame.
- */
- private static void installControlFrames() {
- UiUtil.closeIfOpen(paintControlsFrame);
-
- recentColors = new ArrayList<>();
-
- paintControlsFrame = new CyderFrame.Builder()
- .setWidth(frameLength)
- .setHeight(230)
- .setTitle("Paint Controls")
- .build();
- paintControlsFrame.setResizable(true);
- paintControlsFrame.setShouldFastClose(true);
-
- CyderGridLayout parentLayout = new CyderGridLayout(1, 2);
-
- CyderGridLayout topLayout = new CyderGridLayout(5, 1);
- CyderPanel topLayoutPanel = new CyderPanel(topLayout);
- parentLayout.addComponent(topLayoutPanel, 0, 0);
-
- CyderGridLayout bottomLayout = new CyderGridLayout(6, 1);
- CyderPanel bottomLayoutPanel = new CyderPanel(bottomLayout);
- parentLayout.addComponent(bottomLayoutPanel, 0, 1);
-
- // vars used for drawing custom component
- final int colorRows = 2;
- final int colorsPerRow = 6;
- final int colorBlockLen = 20;
- final int padding = 5;
-
- recentColorsBlock = new JLabel() {
- @Override
- protected void paintComponent(Graphics g) {
- g.translate(0, 10);
- g.setColor(Color.BLACK);
- g.fillRect(0, 0, colorsPerRow * colorBlockLen + 2 * padding, 50);
- g.setColor(CyderColors.vanilla);
- g.fillRect(padding, padding, colorsPerRow * colorBlockLen, 40);
-
- int numColorsPainted = 0;
- int currentX = padding;
- int currentY = padding;
-
- // paint 10 colors at most
- while (numColorsPainted < Math.min(colorRows * colorsPerRow, recentColors.size())) {
- g.setColor(recentColors.get(recentColors.size() - numColorsPainted - 1));
- g.fillRect(currentX, currentY, colorBlockLen, colorBlockLen);
-
- currentX += colorBlockLen;
-
- if (currentX >= padding + colorsPerRow * colorBlockLen) {
- currentX = padding;
- currentY += colorBlockLen;
- }
-
- numColorsPainted++;
- }
-
- // draw sep lines between colors
- g.setColor(Color.BLACK);
- // horizontal lines
- for (int i = 0 ; i < colorRows ; i++) {
- g.drawLine(0, padding + colorBlockLen,
- 2 * padding + colorsPerRow * colorBlockLen, padding + colorBlockLen);
- }
- // vertical lines
- for (int i = 0 ; i < colorsPerRow ; i++) {
- g.drawLine(padding + i * colorBlockLen, 0, padding + i * colorBlockLen,
- 2 * padding + colorRows * colorBlockLen);
- }
- }
- };
- recentColorsBlock.setSize(130, 60);
- recentColorsBlock.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- int x = e.getX();
- int y = e.getY();
-
- // sub padding from both
- x -= padding;
- y -= padding;
-
- // figure out grid points
- int xGrid = x / colorBlockLen;
- int yGrid = y / colorBlockLen;
- int revIndex = xGrid + yGrid * colorsPerRow;
-
- // make sure in bounds
- if (recentColors.size() < 1 + revIndex)
- return;
-
- // get clicked color and set
- setNewPaintColor(recentColors.get(recentColors.size() - 1 - revIndex));
- }
- });
- topLayout.addComponent(recentColorsBlock, 0, 0);
-
- colorHexField = new CyderTextField(11);
- colorHexField.setHorizontalAlignment(JTextField.CENTER);
- colorHexField.setToolTipText("Format: 45FF00 for hex or 255,255,255 for rgb");
- colorHexField.setBounds(0, 40, 110, 40);
- colorHexField.setKeyEventRegexMatcher(CyderRegexPatterns.rgbOrHex.pattern());
- colorHexField.addActionListener(e -> {
- String text = colorHexField.getText();
-
- if (text.contains(CyderStrings.comma)) {
- String[] parts = text.split(CyderStrings.comma);
-
- if (parts.length != 3) {
- paintControlsFrame.notify("Could not parse color");
- } else {
- try {
- int r = Integer.parseInt(parts[0]);
- int g = Integer.parseInt(parts[1]);
- int b = Integer.parseInt(parts[2]);
-
- Color newColor = new Color(r, g, b);
- setNewPaintColor(newColor);
- } catch (Exception ignored) {
- paintControlsFrame.notify("Could not parse color");
- }
- }
- } else {
- try {
- Color newColor = ColorUtil.hexStringToColor(colorHexField.getText());
- setNewPaintColor(newColor);
- } catch (Exception ignored) {
- paintControlsFrame.notify("Could not parse color");
- }
- }
- });
- colorHexField.setText(ColorUtil.toRgbHexString(currentPaintColor));
-
- CyderGridLayout innerLayout = new CyderGridLayout(1, 2);
-
- CyderLabel colorTextLabel = new CyderLabel("New Color");
- colorTextLabel.setBounds(5, 5, 100, 40);
- innerLayout.addComponent(colorTextLabel, 0, 0);
-
- innerLayout.addComponent(colorHexField, 0, 1);
- CyderPanel innerPanel = new CyderPanel(innerLayout);
-
- topLayout.addComponent(innerPanel, 1, 0);
-
- JLabel historyLabel = new JLabel();
- historyLabel.setSize(120, 100);
-
- CyderLabel undoLabel = new CyderLabel("Undo");
- undoLabel.setBounds(5, 5, 50, 30);
- historyLabel.add(undoLabel);
-
- CyderLabel redoLabel = new CyderLabel("Redo");
- redoLabel.setBounds(5 + 52 + 10, 5, 50, 30);
- historyLabel.add(redoLabel);
-
- ImageIcon undoDefault = StaticUtil.getImageIcon("undo.png");
- ImageIcon undoHoverAndFocus = StaticUtil.getImageIcon("undo_hover.png");
- CyderIconButton undo = new CyderIconButton.Builder("Undo", undoDefault, undoHoverAndFocus)
- .setClickAction(() -> {
- cyderGrid.backwardState();
- cyderGrid.revalidate();
- cyderGrid.repaint();
- paintFrame.revalidate();
- paintFrame.repaint();
- }).build();
- undo.setLocation(5, 100 - 60);
- historyLabel.add(undo);
-
- ImageIcon redoDefault = StaticUtil.getImageIcon("redo.png");
- ImageIcon redoFocusHover = StaticUtil.getImageIcon("redo_hover.png");
- CyderIconButton redo = new CyderIconButton.Builder("Redo", redoDefault, redoFocusHover)
- .setClickAction(() -> {
- cyderGrid.forwardState();
- cyderGrid.revalidate();
- cyderGrid.repaint();
- paintFrame.revalidate();
- paintFrame.repaint();
- }).build();
- redo.setLocation(5 + 52 + 10, 100 - 60);
- historyLabel.add(redo);
-
- topLayout.addComponent(historyLabel, 2, 0);
-
- JLabel checkBoxLabel = new JLabel();
- checkBoxLabel.setSize(120, 100);
-
- CyderCheckboxGroup group = new CyderCheckboxGroup();
-
- CyderLabel addLabel = new CyderLabel("Add");
- addLabel.setBounds(5, 5, 50, 30);
- checkBoxLabel.add(addLabel);
-
- addNodesCheckbox = new CyderCheckbox();
- addNodesCheckbox.setToolTipText("Paint cells");
- addNodesCheckbox.setBounds(5, 100 - 55, 50, 50);
- addNodesCheckbox.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- cyderGrid.setMode(CyderGrid.Mode.ADD);
- }
- });
- group.addCheckbox(addNodesCheckbox);
- addNodesCheckbox.setChecked();
- checkBoxLabel.add(addNodesCheckbox);
-
- CyderLabel deleteLabel = new CyderLabel("Delete");
- deleteLabel.setBounds(5 + 50 + 10, 5, 50, 30);
- checkBoxLabel.add(deleteLabel);
-
- CyderCheckbox delete = new CyderCheckbox();
- delete.setBounds(5 + 50 + 10, 100 - 55, 50, 50);
- delete.setToolTipText("Delete cells");
- delete.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- cyderGrid.setMode(CyderGrid.Mode.DELETE);
- }
- });
- group.addCheckbox(delete);
- checkBoxLabel.add(delete);
-
- topLayout.addComponent(checkBoxLabel, 3, 0);
-
- JLabel sliderLabel = new JLabel();
- sliderLabel.setSize(140, 80);
-
- brushWidth = DEFAULT_BRUSH_WIDTH;
-
- CyderLabel brushLabel = new CyderLabel("Brush width: " + brushWidth);
- brushLabel.setBounds(10, 5, 120, 40);
- sliderLabel.add(brushLabel);
-
- JSlider brushWidthSlider = new JSlider(JSlider.HORIZONTAL, MIN_BRUSH_WIDTH,
- MAX_BRUSH_WIDTH, brushWidth);
- CyderSliderUi UI = new CyderSliderUi(brushWidthSlider);
- UI.setThumbStroke(new BasicStroke(2.0f));
- UI.setThumbShape(ThumbShape.RECTANGLE);
- UI.setThumbFillColor(Color.black);
- UI.setThumbOutlineColor(CyderColors.navy);
- UI.setRightThumbColor(CyderColors.regularBlue);
- UI.setLeftThumbColor(CyderColors.regularPink);
- UI.setTrackStroke(new BasicStroke(3.0f));
- brushWidthSlider.setUI(UI);
- brushWidthSlider.setSize(250, 40);
- brushWidthSlider.setPaintTicks(false);
- brushWidthSlider.setPaintLabels(false);
- brushWidthSlider.setVisible(true);
- brushWidthSlider.setValue(brushWidth);
- brushWidthSlider.addChangeListener(e -> {
- int newWidth = brushWidthSlider.getValue();
- brushWidth = newWidth;
- brushLabel.setText("Brush width: " + newWidth);
- cyderGrid.setDrawWidth(brushWidth);
- });
- brushWidthSlider.setOpaque(false);
- brushWidthSlider.setToolTipText("Brush Width");
- brushWidthSlider.setFocusable(false);
- brushWidthSlider.repaint();
- brushWidthSlider.setBounds(10, 40, 120, 40);
- sliderLabel.add(brushWidthSlider);
-
- topLayout.addComponent(sliderLabel, 4, 0);
-
- ImageIcon selectionDefault = StaticUtil.getImageIcon("select.png");
- ImageIcon selectionHoverFocus = StaticUtil.getImageIcon("select_hover.png");
- selectionTool = new CyderIconButton.Builder("Select Region",
- selectionDefault, selectionHoverFocus)
- .setClickAction(PaintWidget::toggleSelectionMode).setToggleButton(true).build();
- selectionTool.setSize(50, 50);
- bottomLayout.addComponent(selectionTool, 0, 0);
-
- ImageIcon cropDefault = StaticUtil.getImageIcon("crop.png");
- ImageIcon cropHoverFocus = StaticUtil.getImageIcon("crop_hover.png");
- CyderIconButton cropToRegion = new CyderIconButton.Builder("Crop Region", cropDefault,
- cropHoverFocus).setClickAction(() -> cyderGrid.cropToSelectedRegion()).build();
- bottomLayout.addComponent(cropToRegion, 1, 0);
-
- ImageIcon cutDefault = StaticUtil.getImageIcon("cut.png");
- ImageIcon cutHoverFocus = StaticUtil.getImageIcon("cut_hover.png");
- CyderIconButton deleteRegion = new CyderIconButton.Builder("Cut Region",
- cutDefault, cutHoverFocus).setClickAction(() -> cyderGrid.deleteSelectedRegion()).build();
- bottomLayout.addComponent(deleteRegion, 2, 0);
-
- ImageIcon selectColorDefault = StaticUtil.getImageIcon("select_color.png");
- ImageIcon selectColorHoverFocus = StaticUtil.getImageIcon("select_color_hover.png");
- selectColor = new CyderIconButton.Builder("Select Color", selectColorDefault, selectColorHoverFocus)
- .setClickAction(PaintWidget::toggleColorSelection).setToggleButton(true).build();
- bottomLayout.addComponent(selectColor, 3, 0);
-
- ImageIcon rotateDefault = StaticUtil.getImageIcon("rotate.png");
- ImageIcon rotateHoverFocus = StaticUtil.getImageIcon("rotate_hover.png");
- CyderIconButton rotate = new CyderIconButton.Builder("Rotate Region", rotateDefault,
- rotateHoverFocus).setClickAction(() -> cyderGrid.rotateRegion()).build();
- bottomLayout.addComponent(rotate, 4, 0);
-
- // selection region reflecting
- ImageIcon reflectDefault = StaticUtil.getImageIcon("reflect.png");
- ImageIcon reflectHoverFocus = StaticUtil.getImageIcon("reflect_hover.png");
- CyderIconButton reflect = new CyderIconButton.Builder("Reflect Region", reflectDefault,
- reflectHoverFocus).setClickAction(() -> cyderGrid.reflectRegionHorizontally()).build();
- bottomLayout.addComponent(reflect, 5, 0);
-
- // use master layout as content pane
- CyderPanel panel = new CyderPanel(parentLayout);
- paintControlsFrame.setCyderLayoutPanel(panel);
-
- // init resizing since we can due to the layout
- paintControlsFrame.initializeResizing();
- paintControlsFrame.setResizable(true);
- paintControlsFrame.setMinimumSize(paintControlsFrame.getSize());
- paintControlsFrame.setMaximumSize(new Dimension(
- (int) (paintControlsFrame.getWidth() * 1.5),
- paintControlsFrame.getHeight()));
- paintControlsFrame.setBackgroundResizing(true);
-
- installDefaultPaintColors();
-
- Rectangle screen = Console.INSTANCE.getConsoleCyderFrame().getMonitorBounds();
- int x = (int) (screen.getX() + (screen.getWidth() - paintControlsFrame.getWidth()) / 2);
- int y = (int) (screen.getHeight() - paintControlsFrame.getHeight()
- - UiUtil.getWindowsTaskbarHeight());
-
- paintControlsFrame.setLocation(x, y);
- paintControlsFrame.setVisible(true);
- paintControlsFrame.setFrameType(FrameType.POPUP);
-
- if (paintFrame.isVisible()) return;
-
- paintFrame.setLocation(x, y - paintFrame.getHeight());
- paintFrame.setVisible(true);
- }
-
- /**
- * The default pallet colors.
- */
- private static final ImmutableList defaultPallet = ImmutableList.of(
- CyderColors.navy,
- CyderColors.regularPink,
- CyderColors.regularOrange,
- CyderColors.regularGreen,
- CyderColors.regularBlue,
- CyderColors.regularPurple
- );
-
- /**
- * Sets up the default paint colors in the pallet.
- */
- private static void installDefaultPaintColors() {
- for (Color paintColor : defaultPallet) {
- setNewPaintColor(paintColor);
- }
- }
-
- /**
- * The default brush width.
- */
- public static final int DEFAULT_BRUSH_WIDTH = 2;
-
- /**
- * The maximum brush width.
- */
- public static final int MAX_BRUSH_WIDTH = 20;
-
- /**
- * The minimum brush width.
- */
- public static final int MIN_BRUSH_WIDTH = 1;
-
- /**
- * The default brush width.
- */
- private static int brushWidth = DEFAULT_BRUSH_WIDTH;
-
- /**
- * Sets the current color and updates the recent colors block
- *
- * @param newColor the new color
- */
- public static void setNewPaintColor(Color newColor) {
- // if no change, ignore
- if (newColor.equals(currentPaintColor))
- return;
-
- // set the current paint
- currentPaintColor = newColor;
-
- // update the hex field with our current color
- if (colorHexField != null)
- colorHexField.setText(ColorUtil.toRgbHexString(newColor));
-
- // ensure if list contains color, it's pulled to the front
- // of recent colors and is not duplicated in the list
- if (recentColors.contains(newColor)) {
- ArrayList newRecentColors = new ArrayList<>();
-
- // add all colors that aren't the new one, remove possible duplicates somehow
- for (Color recentColor : recentColors) {
- if (!recentColor.equals(newColor) && !newRecentColors.contains(recentColor))
- newRecentColors.add(recentColor);
- }
-
- // add the new one to the end
- newRecentColors.add(newColor);
-
- // set recent colors to new object
- recentColors = newRecentColors;
- } else {
- recentColors.add(newColor);
- }
-
- // repaint block to update colors
- recentColorsBlock.repaint();
-
- // set grid's paint
- cyderGrid.setNodeColor(currentPaintColor);
-
- // ensure everything reflects the mode being adding cells
- resetToAdding();
- selectionTool.reset();
- }
-
- /**
- * Handles the button press for selection mode.
- */
- private static void toggleSelectionMode() {
- CyderGrid.Mode newMode = cyderGrid.getMode() == CyderGrid.Mode.SELECTION
- ? CyderGrid.Mode.ADD : CyderGrid.Mode.SELECTION;
-
- resetToAdding();
-
- if (newMode == CyderGrid.Mode.SELECTION) {
- paintFrame.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
- cyderGrid.setMode(CyderGrid.Mode.SELECTION);
- } else {
- paintFrame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
-
- if (addNodesCheckbox.isEnabled()) {
- cyderGrid.setMode(CyderGrid.Mode.ADD);
- } else {
- cyderGrid.setMode(CyderGrid.Mode.DELETE);
- }
- }
-
- Toolkit.getDefaultToolkit().sync();
- }
-
- /**
- * The icon used for color selection mode
- */
- private static final ImageIcon colorSelectionIcon = StaticUtil.getImageIcon("select_color.png");
-
- /**
- * The cursor used when color selection is toggled on.
- */
- private static final Cursor eyedropperCursor = Toolkit.getDefaultToolkit()
- .createCustomCursor(colorSelectionIcon.getImage(), new Point(0, 30), "eyedropper");
-
- /**
- * Toggles between states for color mode selection.
- */
- private static void toggleColorSelection() {
- CyderGrid.Mode newMode = cyderGrid.getMode() == CyderGrid.Mode.COLOR_SELECTION
- ? CyderGrid.Mode.ADD : CyderGrid.Mode.COLOR_SELECTION;
-
- resetToAdding();
- selectionTool.reset();
-
- if (newMode == CyderGrid.Mode.COLOR_SELECTION) {
- cyderGrid.setMode(newMode);
- paintFrame.setCursor(eyedropperCursor);
- } else {
- paintFrame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
-
- if (addNodesCheckbox.isEnabled()) {
- cyderGrid.setMode(CyderGrid.Mode.ADD);
- } else {
- cyderGrid.setMode(CyderGrid.Mode.DELETE);
- }
- }
-
- Toolkit.getDefaultToolkit().sync();
- }
-
- /**
- * Resets all icons to their default state, the mode to adding,
- * and refreshes the checkboxes.
- */
- private static void resetToAdding() {
- // refresh add/delete buttons
- addNodesCheckbox.setChecked();
-
- // de-select toggle-able buttons
- selectColor.setIcon(StaticUtil.getImageIcon("select_color.png"));
-
- // reset grid mode
- cyderGrid.setMode(CyderGrid.Mode.ADD);
-
- // reset cursor
- paintFrame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
- }
-}
diff --git a/src/main/java/cyder/widgets/PathFinderWidget.java b/src/main/java/cyder/widgets/PathFinderWidget.java
deleted file mode 100644
index 707895a05..000000000
--- a/src/main/java/cyder/widgets/PathFinderWidget.java
+++ /dev/null
@@ -1,1400 +0,0 @@
-package cyder.widgets;
-
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.exceptions.IllegalMethodException;
-import cyder.handlers.internal.ExceptionHandler;
-import cyder.math.NumberUtil;
-import cyder.strings.CyderStrings;
-import cyder.threads.CyderThreadRunner;
-import cyder.threads.ThreadUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.drag.CyderDragLabel;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.grid.CyderGrid;
-import cyder.ui.grid.GridNode;
-import cyder.ui.label.CyderLabel;
-import cyder.ui.selection.CyderCheckbox;
-import cyder.ui.selection.CyderCheckboxGroup;
-import cyder.ui.selection.CyderSwitch;
-import cyder.ui.selection.CyderSwitchState;
-import cyder.ui.slider.CyderSliderUi;
-import cyder.ui.slider.ThumbShape;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Optional;
-import java.util.PriorityQueue;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * A pathfinding widget to visualize Dijkstra's path finding algorithm and the A* algorithm
- * with Euclidean distance and Manhattan distance as valid A* heuristics.
- */
-@Vanilla
-@CyderAuthor
-public final class PathFinderWidget {
- /**
- * The pathfinding frame.
- */
- private static CyderFrame pathFindingFrame;
-
- /**
- * The grid component for the visualization.
- */
- private static CyderGrid pathfindingGrid;
-
- /**
- * The default number of nodes for the path grid.
- */
- private static final int DEFAULT_NODES = 25;
-
- /**
- * The maximum number of nodes for the path grid.
- */
- private static final int MAX_NODES = 100;
-
- /**
- * The checkbox dictating whether to perform an animation of the
- * A* algorithm or instantly solve the problem if possible.
- */
- private static CyderCheckbox showStepsBox;
-
- /**
- * The checkbox dictating whether pathing to a diagonal neighbor is allowable.
- */
- private static CyderCheckbox diagonalBox;
-
- /**
- * The checkbox dictating whether the grid mode is ADD or DELETE.
- */
- private static CyderCheckbox deleteWallsCheckBox;
-
- /**
- * The checkbox to place the starting node.
- */
- private static CyderCheckbox placeStartBox;
-
- /**
- * The checkbox to place the goal node.
- */
- private static CyderCheckbox placeGoalBox;
-
- /**
- * The checkbox dictating whether to draw grid lines on the grid.
- */
- private static CyderCheckbox drawGridLinesBox;
-
- /**
- * The heuristic switcher to switch between Euclidean and
- * Manhattan distances as heuristics for A*.
- */
- private static CyderSwitch heuristicSwitch;
-
- /**
- * The off text for the heuristic switch.
- */
- private static final String HEURISTIC_OFF = "Manhattan";
-
- /**
- * The on text for the heuristic switch.
- */
- private static final String HEURISTIC_ON = "Euclidean";
-
- /**
- * The algorithm switcher to switch between A* and Dijkstra's.
- */
- private static CyderSwitch algorithmSwitch;
-
- /**
- * The text to use for the algorithm OFF state.
- */
- private static final String ALGORITHM_OFF = "A*";
-
- /**
- * The text to use for the algorithm ON state.
- */
- private static final String ALGORITHM_ON = "Dijkstras";
-
- /**
- * The button to start/pause the animation.
- */
- private static CyderButton startPauseButton;
-
- /**
- * The slider to determine the speed of the animation.
- */
- private static JSlider speedSlider;
-
- /**
- * The maximum slider value.
- */
- private static final int MAX_SLIDER_VALUE = 100;
-
- /**
- * The minimum slider value.
- */
- private static final int MIN_SLIDER_VALUE = 1;
-
- /**
- * The default slider value in between the min and max values.
- */
- private static final int DEFAULT_SLIDER_VALUE = (MIN_SLIDER_VALUE + MAX_SLIDER_VALUE) / 2;
-
- /**
- * The timeout in ms between the path animation refresh.
- */
- private static final int PATH_TRICKLE_TIMEOUT = 30;
-
- /**
- * The current state of the A* algorithm.
- */
- private static PathingState currentPathingState = PathingState.NOT_STARTED;
-
- /**
- * The valid states of the A* algorithm.
- */
- private enum PathingState {
- /**
- * The algorithm is finished and found a path.
- */
- PATH_FOUND("Path found"),
- /**
- * The algorithm is finished but no path was found. :(
- */
- PATH_NOT_FOUND("No path found"),
- /**
- * The algorithm is incomplete and may be resumed.
- */
- PAUSED("Paused"),
- /**
- * The algorithm has not yet begun (Widget just opened or reset invoked).
- */
- NOT_STARTED("Not Started"),
- /**
- * The algorithm is currently underway, whether this be the first time it
- * has begun, or the 1000th time it has been paused and resumed.
- */
- RUNNING("Running...");
-
- /**
- * The state label text for this pathing state.
- */
- private final String stateLabelText;
-
- PathingState(String stateLabelText) {
- this.stateLabelText = stateLabelText;
- }
-
- /**
- * Returns the state label text for this pathing state.
- *
- * @return the state label text for this pathing state
- */
- public String getStateLabelText() {
- return stateLabelText;
- }
- }
-
- /**
- * The label to display the current state on.
- */
- private static CyderLabel currentStateLabel;
-
- /**
- * The color used for pathable nodes in the open list
- */
- private static final Color pathableOpenColor = new Color(254, 104, 88);
-
- /**
- * The color used for pathable nodes that have been removed from the open list.
- */
- private static final Color pathableClosedColor = new Color(121, 236, 135);
-
- /**
- * The color used for walls.
- */
- private static final Color wallsColor = CyderColors.navy;
-
- /**
- * The color used for the goal node.
- */
- private static final Color goalNodeColor = CyderColors.regularOrange;
-
- /**
- * The color used for the start node.
- */
- private static final Color startNodeColor = CyderColors.regularPink;
-
- /**
- * The node which the pathfinding starts from.
- * By default this is the top left corner (0,0).
- */
- private static PathNode startNode;
-
- /**
- * The node which A* attempts to path to.
- * By default this is the bottom right corner (DEFAULT_NODES - 1, DEFAULT_NODES - 1).
- */
- private static PathNode goalNode;
-
- /**
- * The default point the starting node is placed at.
- */
- private static final Point DEFAULT_START_POINT = new Point(0, 0);
-
- /**
- * The default point the goal node is placed at.
- */
- private static final Point DEFAULT_GOAL_POINT = new Point(DEFAULT_NODES - 1, DEFAULT_NODES - 1);
-
- /**
- * The font to use for the state label.
- */
- private static final Font STATE_LABEL_FONT = new Font("Agency FB", Font.BOLD, 40);
-
- /**
- * The nodes which may be pathed through on the current grid state.
- */
- private static final ArrayList pathableNodes = new ArrayList<>();
-
- /**
- * The nodes which are in the queue to be pathed through.
- */
- private static final PriorityQueue openNodes = new PriorityQueue<>(new NodeComparator());
-
- /**
- * The current path animation object.
- * This is always killed before being set to a new object,
- * similar to how things are handled in AudioPlayer.
- */
- private static PathTrickleAnimator currentPathAnimator;
-
- /**
- * The path solver thread name.
- */
- private static final String PATH_SOLVING_THREAD_NAME = "Path Solver";
-
- /**
- * The semaphore used to achieve thread safety when
- * adding/removing to/from the grid and repainting.
- */
- private static final Semaphore semaphore = new Semaphore(1);
-
- /**
- * The heuristic value for A* to be logically equivalent to Dijkstra's.
- */
- private static final int DIJKSTRA_HEURISTIC = 1;
-
- /**
- * The width of the frame.
- */
- private static final int FRAME_WIDTH = 1000;
-
- /**
- * The height of the frame.
- */
- private static final int FRAME_HEIGHT = 1070;
-
- /**
- * The widget title.
- */
- private static final String TITLE = "Pathfinding Visualizer";
-
- /**
- * The length of the grid component.
- */
- private static final int gridComponentLength = 800;
-
- /**
- * The text for the start button.
- */
- private static final String START = "Start";
-
- /**
- * The text for the reset button.
- */
- private static final String RESET = "Reset";
-
- /**
- * The text for the stop button.
- */
- private static final String STOP = "Stop";
-
- /**
- * The state label string prefix.
- */
- private static final String STATE = "State:";
-
- /**
- * The text for the resume button.
- */
- private static final String RESUME = "Resume";
-
- /**
- * Suppress default constructor.
- */
- private PathFinderWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Widget(triggers = {"path", "pathfinder", "A*"},
- description = "A pathfinding visualizer for A* and Dijkstras algorithms")
- public static void showGui() {
- UiUtil.closeIfOpen(pathFindingFrame);
-
- pathFindingFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(TITLE)
- .build();
-
- pathfindingGrid = new CyderGrid(DEFAULT_NODES, gridComponentLength);
- pathfindingGrid.setBounds(100, 80, gridComponentLength, gridComponentLength);
- pathfindingGrid.setMinNodes(DEFAULT_NODES);
- pathfindingGrid.setMaxNodes(MAX_NODES);
- pathfindingGrid.setDrawGridLines(true);
- pathfindingGrid.setBackground(CyderColors.vanilla);
- pathfindingGrid.setResizable(true);
- pathfindingGrid.addOnResizeCallback(() -> {
- ArrayList goals = pathfindingGrid.getNodesOfColor(goalNodeColor);
- if (goals.size() == 1) {
- GridNode localGoal = goals.get(0);
- int maxGoalCoordinate = Math.max(localGoal.getX(), localGoal.getY());
- if (maxGoalCoordinate >= pathfindingGrid.getNodeDimensionLength()) {
- pathfindingGrid.removeNodesOfColor(goalNodeColor);
- }
- }
-
- ArrayList starts = pathfindingGrid.getNodesOfColor(startNodeColor);
- if (starts.size() == 1) {
- GridNode localStart = starts.get(0);
- int maxStartCoordinate = Math.max(localStart.getX(), localStart.getY());
- if (maxStartCoordinate >= pathfindingGrid.getNodeDimensionLength()) {
- pathfindingGrid.removeNodesOfColor(startNodeColor);
- }
- }
- });
- pathfindingGrid.setSmoothScrolling(true);
- pathFindingFrame.getContentPane().add(pathfindingGrid);
- pathfindingGrid.setSaveStates(false);
-
- currentStateLabel = new CyderLabel();
- currentStateLabel.setFont(STATE_LABEL_FONT);
- currentStateLabel.setBounds(40, CyderDragLabel.DEFAULT_HEIGHT,
- pathFindingFrame.getWidth() - 80, 50);
- pathFindingFrame.getContentPane().add(currentStateLabel);
-
- int startY = pathfindingGrid.getY() + pathfindingGrid.getHeight();
- int startX = pathfindingGrid.getX();
-
- CyderLabel placeStartLabel = new CyderLabel("Start");
- placeStartLabel.setBounds(startX - 50, startY + 5, 150, 40);
- pathFindingFrame.getContentPane().add(placeStartLabel);
-
- placeStartBox = new CyderCheckbox();
- placeStartBox.setToolTipText("Place start node");
- placeStartBox.setBounds(startX, startY + 40, 50, 50);
- pathFindingFrame.getContentPane().add(placeStartBox);
- placeStartBox.addMouseListener(placeStartBoxMouseListener);
-
- CyderLabel placeGoalLabel = new CyderLabel("Goal");
- placeGoalLabel.setBounds(startX - 50 + 80, startY + 5, 150, 40);
- pathFindingFrame.getContentPane().add(placeGoalLabel);
-
- placeGoalBox = new CyderCheckbox();
- placeGoalBox.setToolTipText("Place goal node");
- placeGoalBox.setBounds(startX + 80, startY + 40, 50, 50);
- pathFindingFrame.getContentPane().add(placeGoalBox);
- placeGoalBox.addMouseListener(placeGoalMouseListener);
-
- CyderCheckboxGroup nodeGroup = new CyderCheckboxGroup();
- nodeGroup.addCheckbox(placeStartBox);
- nodeGroup.addCheckbox(placeGoalBox);
-
- CyderLabel deleteWallsLabel = new CyderLabel("Delete walls");
- deleteWallsLabel.setBounds(startX - 50 + 80 * 2, startY + 5, 150, 40);
- pathFindingFrame.getContentPane().add(deleteWallsLabel);
-
- deleteWallsCheckBox = new CyderCheckbox();
- deleteWallsCheckBox.setToolTipText("Delete Walls");
- deleteWallsCheckBox.setBounds(startX + 80 * 2, startY + 40, 50, 50);
- pathFindingFrame.getContentPane().add(deleteWallsCheckBox);
- deleteWallsCheckBox.addMouseListener(deleteWallsMouseListener);
-
- CyderLabel showStepsLabel = new CyderLabel("Steps");
- showStepsLabel.setBounds(startX - 50, startY + 5 + 80, 150, 40);
- pathFindingFrame.getContentPane().add(showStepsLabel);
-
- showStepsBox = new CyderCheckbox();
- showStepsBox.setToolTipText("Show steps");
- showStepsBox.setBounds(startX, startY + 40 + 80, 50, 50);
- pathFindingFrame.getContentPane().add(showStepsBox);
-
- CyderLabel allowDiagonalsLabel = new CyderLabel("Diagonals");
- allowDiagonalsLabel.setBounds(startX - 50 + 80, startY + 5 + 80, 150, 40);
- pathFindingFrame.getContentPane().add(allowDiagonalsLabel);
-
- diagonalBox = new CyderCheckbox();
- diagonalBox.setToolTipText("Allow diagonals");
- diagonalBox.setBounds(startX + 80, startY + 40 + 80, 50, 50);
- pathFindingFrame.getContentPane().add(diagonalBox);
-
- CyderLabel drawGridLinesLabel = new CyderLabel("Grid Lines");
- drawGridLinesLabel.setBounds(startX - 50 + 80 * 2, startY + 5 + 80, 150, 40);
- pathFindingFrame.getContentPane().add(drawGridLinesLabel);
-
- drawGridLinesBox = new CyderCheckbox();
- drawGridLinesBox.setToolTipText("Draw grid lines");
- drawGridLinesBox.setBounds(startX + 80 * 2, startY + 40 + 80, 50, 50);
- drawGridLinesBox.addMouseListener(drawGridLinesMouseListener);
- pathFindingFrame.getContentPane().add(drawGridLinesBox);
-
- CyderButton reset = new CyderButton(RESET);
- reset.setBounds(350, startY + 40 - 20, 180, 50);
- reset.addActionListener(e -> reset());
- pathFindingFrame.getContentPane().add(reset);
-
- startPauseButton = new CyderButton(START);
- startPauseButton.setBounds(350, startY + 40 + 80, 180, 50);
- startPauseButton.addActionListener(e -> startPauseButtonAction());
- pathFindingFrame.getContentPane().add(startPauseButton);
-
- heuristicSwitch = new CyderSwitch(350, 50);
- heuristicSwitch.setOffText(HEURISTIC_OFF);
- heuristicSwitch.setOnText(HEURISTIC_ON);
- heuristicSwitch.setToolTipText("A* Heuristic");
- heuristicSwitch.setBounds(550, startY + 40 - 20, 350, 50);
- heuristicSwitch.setButtonPercent(50);
- pathFindingFrame.getContentPane().add(heuristicSwitch);
-
- speedSlider = new JSlider(JSlider.HORIZONTAL, MIN_SLIDER_VALUE,
- MAX_SLIDER_VALUE, DEFAULT_SLIDER_VALUE);
- CyderSliderUi speedSliderUi = new CyderSliderUi(speedSlider);
- speedSliderUi.setThumbStroke(new BasicStroke(2.0f));
- speedSliderUi.setThumbShape(ThumbShape.RECTANGLE);
- speedSliderUi.setThumbFillColor(Color.black);
- speedSliderUi.setThumbOutlineColor(CyderColors.navy);
- speedSliderUi.setRightThumbColor(CyderColors.regularBlue);
- speedSliderUi.setLeftThumbColor(CyderColors.regularPink);
- speedSliderUi.setTrackStroke(new BasicStroke(3.0f));
- speedSlider.setUI(speedSliderUi);
- speedSlider.setBounds(350, startY + 40 + 35, 350 + 180 + 20, 40);
- speedSlider.setPaintTicks(false);
- speedSlider.setPaintLabels(false);
- speedSlider.setVisible(true);
- speedSlider.setOpaque(false);
- speedSlider.setToolTipText("Pathfinding Speed");
- speedSlider.setFocusable(false);
- pathFindingFrame.getContentPane().add(speedSlider);
-
- algorithmSwitch = new CyderSwitch(350, 50);
- algorithmSwitch.setOffText(ALGORITHM_OFF);
- algorithmSwitch.setOnText(ALGORITHM_ON);
- algorithmSwitch.setToolTipText("Algorithm Switcher");
- algorithmSwitch.setBounds(550, startY + 40 + 80, 350, 50);
- algorithmSwitch.setButtonPercent(50);
- pathFindingFrame.getContentPane().add(algorithmSwitch);
-
- reset();
-
- pathFindingFrame.finalizeAndShow();
- }
-
- /**
- * The mouse listener for the place start checkbox.
- */
- private static final MouseListener placeStartBoxMouseListener = new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- super.mouseClicked(e);
- if (placeStartBox.isChecked()) {
- pathfindingGrid.setNodeColor(startNodeColor);
-
- pathfindingGrid.removeInvokeWhenNodePlacedRunnables();
- pathfindingGrid.invokeWhenNodePlaced(() -> {
- pathfindingGrid.removeNodesOfColor(startNodeColor);
-
- placeStartBox.setNotChecked();
- pathfindingGrid.setNodeColor(wallsColor);
- });
-
- deleteWallsCheckBox.setNotChecked();
- pathfindingGrid.setMode(CyderGrid.Mode.ADD);
- } else {
- pathfindingGrid.removeInvokeWhenNodePlacedRunnables();
- pathfindingGrid.setNodeColor(wallsColor);
- }
- }
- };
-
- /**
- * The mouse listener for the place goal checkbox.
- */
- private static final MouseListener placeGoalMouseListener = new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- super.mouseClicked(e);
- if (placeGoalBox.isChecked()) {
- pathfindingGrid.setNodeColor(goalNodeColor);
-
- pathfindingGrid.removeInvokeWhenNodePlacedRunnables();
- pathfindingGrid.invokeWhenNodePlaced(() -> {
- pathfindingGrid.removeNodesOfColor(goalNodeColor);
-
- placeGoalBox.setNotChecked();
- pathfindingGrid.setNodeColor(wallsColor);
- });
-
- deleteWallsCheckBox.setNotChecked();
- pathfindingGrid.setMode(CyderGrid.Mode.ADD);
- } else {
- pathfindingGrid.removeInvokeWhenNodePlacedRunnables();
- pathfindingGrid.setNodeColor(wallsColor);
- }
- }
- };
-
- /**
- * The mouse listener for the delete walls checkbox.
- */
- private static final MouseListener deleteWallsMouseListener = new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- super.mouseClicked(e);
-
- if (pathfindingGrid.getMode() == CyderGrid.Mode.ADD) {
- pathfindingGrid.setMode(CyderGrid.Mode.DELETE);
- } else {
- pathfindingGrid.setMode(CyderGrid.Mode.ADD);
- }
- }
- };
-
- /**
- * The mouse listener for the draw grid lines checkbox.
- */
- private static final MouseListener drawGridLinesMouseListener = new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- super.mouseClicked(e);
- pathfindingGrid.setDrawGridLines(drawGridLinesBox.isChecked());
- }
- };
-
- /**
- * The actions to invoke when the start/pause button is pressed.
- */
- private static void startPauseButtonAction() {
- if (pathfindingGrid.getNodesOfColor(startNodeColor).isEmpty()) {
- pathFindingFrame.notify("Start node not set");
- return;
- }
-
- if (pathfindingGrid.getNodesOfColor(goalNodeColor).isEmpty()) {
- pathFindingFrame.notify("End node not set");
- return;
- }
-
- if (currentPathingState == PathingState.RUNNING) {
- currentPathingState = PathingState.PAUSED;
- startPauseButton.setText(RESUME);
- updateStateLabel();
- enableUiElements();
- return;
- }
-
- disableUiElements();
- startPauseButton.setText(STOP);
-
- if (currentPathingState == PathingState.PAUSED) {
- currentPathingState = PathingState.RUNNING;
- startPathStepLoop();
- } else {
- searchSetup();
- }
- }
-
- /**
- * Performs the setup necessary to start path finding such as
- * initializing the lists, finding the start and goal nodes,
- * and converting GridNodes to PathNodes.
- */
- private static void searchSetup() {
- /*
- This method is only invoked if start and goal nodes are set.
- */
-
- endPathAnimator();
- removePathingNodes();
-
- ArrayList walls = pathfindingGrid.getNodesOfColor(wallsColor);
-
- GridNode gridGoal = pathfindingGrid.getNodesOfColor(goalNodeColor).get(0);
- goalNode = new PathNode(gridGoal.getX(), gridGoal.getY());
- goalNode.setParent(null);
-
- GridNode gridStart = pathfindingGrid.getNodesOfColor(startNodeColor).get(0);
- startNode = new PathNode(gridStart.getX(), gridStart.getY());
- startNode.setParent(null);
-
- pathableNodes.clear();
- for (int x = 0 ; x < pathfindingGrid.getNodeDimensionLength() ; x++) {
- for (int y = 0 ; y < pathfindingGrid.getNodeDimensionLength() ; y++) {
- GridNode node = new GridNode(x, y);
-
- /*
- Ignore walls for pathable nodes.
-
- Note to maintainers: if future node types are added and should not be pathable,
- they should be tested for here.
- */
- if (walls.contains(node)) {
- continue;
- }
-
- pathableNodes.add(new PathNode(node.getX(), node.getY()));
- }
- }
-
- startNode.setG(0);
- startNode.setH(heuristic(goalNode));
-
- openNodes.clear();
- openNodes.add(startNode);
-
- currentPathingState = PathingState.RUNNING;
-
- disableUiElements();
-
- pathfindingGrid.setResizable(false);
-
- startPathStepLoop();
- }
-
- /**
- * Starts the main while loop which takes path steps until a path is
- * found or all reachable nodes have been checked.
- * All setup of lists must be performed before invoking this method.
- */
- private static void startPathStepLoop() {
- updateStateLabel();
-
- CyderThreadRunner.submit(() -> {
- while (currentPathingState == PathingState.RUNNING) {
- pathStep();
-
- if (showStepsBox.isChecked()) {
- lockingRepaintGrid();
- ThreadUtil.sleep(MAX_SLIDER_VALUE - speedSlider.getValue());
- }
- }
- }, PATH_SOLVING_THREAD_NAME);
- }
-
- /**
- * Takes a step towards the goal node according to
- * the current heuristic and pathable nodes.
- *
- * This is equivalent to what is computed in the primary A* while loop.
- * A future feature could be added to allow the algorithm to be
- * stepped through via this method.
- */
- private static void pathStep() {
- if (!openNodes.isEmpty()) {
- PathNode min = openNodes.poll();
-
- if (min.equals(goalNode)) {
- goalNode.setParent(min.getParent());
-
- pathFound();
- return;
- }
-
- ArrayList neighbors = new ArrayList<>();
- for (PathNode possibleNeighbor : pathableNodes) {
- if (areOrthogonalNeighbors(possibleNeighbor, min)
- || (areDiagonalNeighbors(possibleNeighbor, min) && diagonalBox.isChecked())) {
- neighbors.add(possibleNeighbor);
- }
- }
-
- neighbors.forEach(neighbor -> {
- double currentHCost = heuristic(neighbor);
-
- if (currentHCost < neighbor.getH()) {
- neighbor.setH(currentHCost);
- neighbor.setParent(min);
- neighbor.setG(min.getG() + euclideanDistance(min, neighbor));
-
- if (!openNodes.contains(neighbor)) {
- openNodes.add(neighbor);
- }
- }
- });
-
- // Refresh grid colors based on current state of algorithm and nodes checked.
- pathableNodes.stream().filter(pathNode -> !pathNode.equals(startNode) && !pathNode.equals(goalNode))
- .forEach(pathNode -> {
- int x = pathNode.getX();
- int y = pathNode.getY();
-
- if (openNodes.contains(pathNode)) {
- lockingAddNode(new GridNode(pathableOpenColor, x, y));
- } else if (pathNode.getParent() != null) {
- lockingAddNode(new GridNode(pathableClosedColor, x, y));
- }
- });
- } else {
- pathNotFound();
- }
- }
-
- /**
- * Performs the actions necessary following a path
- * from the start to the goal node being found.
- */
- private static void pathFound() {
- currentPathingState = PathingState.PATH_FOUND;
-
- startPauseButton.setText(START);
-
- enableUiElements();
- updateStateLabel();
-
- pathfindingGrid.setResizable(true);
-
- ArrayList pathForward = new ArrayList<>();
-
- PathNode refNode = goalNode.getParent();
- while (refNode != startNode) {
- pathForward.add(new Point(refNode.getX(), refNode.getY()));
- refNode = refNode.getParent();
- }
-
- ArrayList pathReversed = new ArrayList<>();
-
- for (int i = pathForward.size() - 1 ; i > -1 ; i--) {
- pathReversed.add(pathForward.get(i));
- }
-
- currentPathAnimator = new PathTrickleAnimator(pathReversed);
- }
-
- /**
- * A animator class to perform the path found animation.
- */
- private static class PathTrickleAnimator {
- /**
- * The trickle animation thread name.
- */
- private static final String PATH_TRICKLE_ANIMATION_THREAD_NAME = "Pathfinding Path Trickle Animator";
-
- /**
- * The color used for the found path.
- */
- private static final Color PATH_COLOR = CyderColors.regularBlue;
-
- /**
- * The color used for the path found animation trickle.
- */
- private static final Color PATH_ANIMATION_COLOR = new Color(34, 216, 248);
-
- /**
- * Whether this animation has been killed
- */
- private final AtomicBoolean killed = new AtomicBoolean(false);
-
- /**
- * Constructs and starts a new path animator.
- *
- * @param pathPoints the list of points to animate
- */
- public PathTrickleAnimator(ArrayList pathPoints) {
- CyderThreadRunner.submit(() -> {
- try {
- // Draw initial path from start to goal
- for (Point pathPoint : pathPoints) {
- if (killed.get()) return;
-
- GridNode updateNode = null;
-
- for (GridNode node : pathfindingGrid.getGridNodes()) {
- if (killed.get()) return;
-
- if (node.getX() == pathPoint.getX() && node.getY() == pathPoint.getY()) {
- updateNode = node;
- break;
- }
- }
-
- Color color = updateNode != null ? updateNode.getColor() : null;
- if (color != null
- && (color.equals(PATH_ANIMATION_COLOR) || color.equals(pathableClosedColor))) {
-
- int x = updateNode.getX();
- int y = updateNode.getY();
- lockingAddNode(new GridNode(PATH_ANIMATION_COLOR, x, y));
-
- lockingRepaintGrid();
- ThreadUtil.sleep(PATH_TRICKLE_TIMEOUT);
- }
- }
-
- while (true) {
- // Trickle from start to goal
- for (Point pathPoint : pathPoints) {
- if (killed.get()) return;
-
- Optional overridePoint = pathfindingGrid.getNodeAtPoint(pathPoint);
- if (overridePoint.isPresent()
- && (overridePoint.get().getColor().equals(PATH_ANIMATION_COLOR)
- || overridePoint.get().getColor().equals(PATH_COLOR))) {
- int x = (int) pathPoint.getX();
- int y = (int) pathPoint.getY();
- lockingAddNode(new GridNode(PATH_COLOR, x, y));
-
- lockingRepaintGrid();
- }
-
- if (killed.get()) return;
- ThreadUtil.sleep(PATH_TRICKLE_TIMEOUT);
- if (killed.get()) return;
-
- overridePoint = pathfindingGrid.getNodeAtPoint(pathPoint);
- if (overridePoint.isPresent()
- && (overridePoint.get().getColor().equals(PATH_ANIMATION_COLOR)
- || overridePoint.get().getColor().equals(PATH_COLOR))) {
-
- int x = (int) pathPoint.getX();
- int y = (int) pathPoint.getY();
- lockingAddNode(new GridNode(PATH_ANIMATION_COLOR, x, y));
- lockingRepaintGrid();
- }
- }
-
- if (killed.get()) return;
-
- // Trickle from goal to start
- for (int i = pathPoints.size() - 1 ; i >= 0 ; i--) {
- Optional overridePoint
- = pathfindingGrid.getNodeAtPoint(pathPoints.get(i));
- if (overridePoint.isPresent()
- && (overridePoint.get().getColor().equals(PATH_ANIMATION_COLOR)
- || overridePoint.get().getColor().equals(PATH_COLOR))) {
- lockingAddNode(new GridNode(PATH_COLOR,
- (int) pathPoints.get(i).getX(),
- (int) pathPoints.get(i).getY()));
- lockingRepaintGrid();
- }
-
- if (killed.get()) return;
- ThreadUtil.sleep(PATH_TRICKLE_TIMEOUT);
- if (killed.get()) return;
-
- overridePoint = pathfindingGrid.getNodeAtPoint(pathPoints.get(i));
- if (overridePoint.isPresent()
- && (overridePoint.get().getColor().equals(PATH_ANIMATION_COLOR)
- || overridePoint.get().getColor().equals(PATH_COLOR))) {
- lockingAddNode(new GridNode(PATH_ANIMATION_COLOR,
- (int) pathPoints.get(i).getX(),
- (int) pathPoints.get(i).getY()));
- lockingRepaintGrid();
- }
-
- if (killed.get()) return;
- }
- }
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
- lockingRepaintGrid();
- }, PATH_TRICKLE_ANIMATION_THREAD_NAME);
- }
-
- /**
- * Kills this path animator.
- */
- public void kill() {
- killed.set(true);
- }
- }
-
- /**
- * Performs the actions necessary following a path
- * from the start to the goal node was not found.
- */
- private static void pathNotFound() {
- currentPathingState = PathingState.PATH_NOT_FOUND;
-
- updateStateLabel();
-
- startPauseButton.setText(START);
-
- enableUiElements();
-
- pathfindingGrid.setResizable(true);
-
- lockingRepaintGrid();
- }
-
- /**
- * Enables the UI elements during the pathfinding animation.
- */
- private static void enableUiElements() {
- setUiElementsEnabled(true);
- }
-
- /**
- * Disables the UI elements during the pathfinding animation.
- */
- private static void disableUiElements() {
- setUiElementsEnabled(false);
- }
-
- /**
- * Sets whether the ui elements are enabled.
- *
- * @param enabled whether the ui elements are enabled
- */
- @ForReadability
- private static void setUiElementsEnabled(boolean enabled) {
- deleteWallsCheckBox.setEnabled(enabled);
- showStepsBox.setEnabled(enabled);
- diagonalBox.setEnabled(enabled);
- placeStartBox.setEnabled(enabled);
- placeGoalBox.setEnabled(enabled);
- drawGridLinesBox.setEnabled(enabled);
-
- heuristicSwitch.setEnabled(enabled);
- algorithmSwitch.setEnabled(enabled);
-
- if (enabled) {
- pathfindingGrid.installClickAndDragPlacer();
- } else {
- pathfindingGrid.uninstallClickAndDragPlacer();
- }
- }
-
- /**
- * Resets all the checkboxes to their default state.
- */
- private static void resetCheckboxStates() {
- deleteWallsCheckBox.setChecked(false);
- showStepsBox.setChecked(false);
- diagonalBox.setChecked(false);
- placeStartBox.setChecked(false);
- placeGoalBox.setChecked(false);
- drawGridLinesBox.setChecked(true);
- pathfindingGrid.setDrawGridLines(true);
- }
-
- /**
- * Resets the algorithm and heuristic switchers to their default states.
- */
- private static void resetSwitcherStates() {
- // Corresponds to Manhattan
- heuristicSwitch.setState(CyderSwitchState.OFF);
- // Corresponds to A*
- algorithmSwitch.setState(CyderSwitchState.OFF);
- }
-
- /**
- * Updates the state label based.
- */
- private static void updateStateLabel() {
- currentStateLabel.setText(STATE + CyderStrings.space + currentPathingState.getStateLabelText());
- }
-
- /**
- * Removes all nodes having to do with the pathfinding algorithm such as
- * open nodes, closed nodes, and blue path nodes.
- * Note this method does not repaint the grid.
- */
- private static void removePathingNodes() {
- pathfindingGrid.removeNodesOfColor(pathableClosedColor);
- pathfindingGrid.removeNodesOfColor(pathableOpenColor);
- }
-
- /**
- * Resets the start and goal nodes to their default.
- * Note this method does not repaint the grid.
- */
- private static void resetStartAndGoalNodes() {
- pathfindingGrid.removeNodesOfColor(startNodeColor);
- pathfindingGrid.removeNodesOfColor(goalNodeColor);
-
- startNode = new PathNode(DEFAULT_START_POINT);
- goalNode = new PathNode(DEFAULT_GOAL_POINT);
-
- lockingAddNode(new GridNode(startNodeColor, startNode.getX(), startNode.getY()));
- lockingAddNode(new GridNode(goalNodeColor, goalNode.getX(), goalNode.getY()));
- }
-
- /**
- * Removes all walls from the grid.
- * Note this method does not repaint the grid.
- */
- private static void removeWalls() {
- pathfindingGrid.removeNodesOfColor(wallsColor);
- }
-
- /**
- * Kills the path animator and sets it to null.
- */
- private static void endPathAnimator() {
- if (currentPathAnimator == null) return;
-
- currentPathAnimator.kill();
- currentPathAnimator = null;
-
- pathfindingGrid.removeNodesOfColor(PathTrickleAnimator.PATH_COLOR);
- pathfindingGrid.removeNodesOfColor(PathTrickleAnimator.PATH_ANIMATION_COLOR);
-
- }
-
- /**
- * Resets the visualizer as if the widget was just opened.
- */
- public static void reset() {
- endPathAnimator();
-
- enableUiElements();
-
- startPauseButton.setText(START);
-
- resetCheckboxStates();
- resetSwitcherStates();
- removePathingNodes();
- resetStartAndGoalNodes();
- removeWalls();
-
- currentPathingState = PathingState.NOT_STARTED;
- updateStateLabel();
-
- pathfindingGrid.setNodeDimensionLength(DEFAULT_NODES);
-
- speedSlider.setValue(DEFAULT_SLIDER_VALUE);
-
- pathfindingGrid.installClickAndDragPlacer();
-
- pathfindingGrid.setResizable(true);
-
- lockingRepaintGrid();
- }
-
- /**
- * Repaints the pathfinding grid in a thread-safe way.
- */
- private static void lockingRepaintGrid() {
- try {
- semaphore.acquire();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- pathfindingGrid.repaint();
- semaphore.release();
- }
-
- /**
- * Adds the node to the pathfinding grid in thread-safe way.
- *
- * @param node the node to add to the grid
- */
- private static void lockingAddNode(GridNode node) {
- try {
- semaphore.acquire();
- } catch (Exception e) {
- ExceptionHandler.handle(e);
- }
-
- pathfindingGrid.addNode(node);
- semaphore.release();
- }
-
- /**
- * Returns whether the provided nodes are diagonal neighbors.
- *
- * @param node1 the first node
- * @param node2 the second node
- * @return whether the provided nodes are diagonal neighbors
- */
- private static boolean areDiagonalNeighbors(PathNode node1, PathNode node2) {
- return (node1.getX() == node2.getX() + 1 && node1.getY() == node2.getY() + 1)
- || (node1.getX() == node2.getX() + 1 && node1.getY() == node2.getY() - 1)
- || (node1.getX() == node2.getX() - 1 && node1.getY() == node2.getY() - 1)
- || (node1.getX() == node2.getX() - 1 && node1.getY() == node2.getY() + 1);
- }
-
- /**
- * Returns whether the provided nodes are orthogonal neighbors.
- *
- * @param node1 the first node
- * @param node2 the second node
- * @return whether the provided nodes are orthogonal neighbors
- */
- private static boolean areOrthogonalNeighbors(PathNode node1, PathNode node2) {
- return (node1.getX() == node2.getX() && node1.getY() == node2.getY() + 1)
- || (node1.getX() == node2.getX() && node1.getY() == node2.getY() - 1)
- || (node1.getX() == node2.getX() + 1 && node1.getY() == node2.getY())
- || (node1.getX() == node2.getX() - 1 && node1.getY() == node2.getY());
- }
-
- /**
- * Calculates the heuristic from the provided node to the goal node
- * using the currently set heuristic.
- *
- * @param node the node to calculate the heuristic of
- * @return the cost to path from the provided node to the goal
- */
- private static double heuristic(PathNode node) {
- boolean dijkstrasAlgorithm = algorithmSwitch.getState() == CyderSwitchState.ON;
- boolean euclideanDistance = heuristicSwitch.getState() == CyderSwitchState.ON;
- if (dijkstrasAlgorithm) {
- return DIJKSTRA_HEURISTIC;
- } else if (euclideanDistance) {
- return euclideanDistance(node, goalNode);
- } else {
- return manhattanDistance(node, goalNode);
- }
- }
-
- /**
- * Calculates the g cost from the provided node to the start node.
- * This uses Euclidean distance by definition of g cost.
- *
- * @param node the node to calculate the g cost of
- * @return the g cost of the provided node
- */
- private static double calcGCost(PathNode node) {
- return euclideanDistance(node, startNode);
- }
-
- /**
- * Returns the Euclidean distance between the two nodes.
- *
- * @param node1 the first noDe
- * @param node2 the second node
- * @return the Euclidean distance between the two nodes
- */
- private static double euclideanDistance(PathNode node1, PathNode node2) {
- return NumberUtil.calculateMagnitude(node1.getX() - node2.getX(),
- node1.getY() - node2.getY());
- }
-
- /**
- * Returns the Manhattan distance between the two nodes.
- *
- * @param node1 the first node
- * @param node2 the second node
- * @return the Manhattan distance between the two nodes
- */
- private static double manhattanDistance(PathNode node1, PathNode node2) {
- return Math.abs(node1.getX() - node2.getX()) + Math.abs(node1.getY() - node2.getY());
- }
-
- /**
- * The node comparator to use for the node queue.
- */
- private static class NodeComparator implements Comparator {
- @Override
- public int compare(PathNode node1, PathNode node2) {
- if (node1.getF() > node2.getF()) {
- return 1;
- } else if (node1.getF() < node2.getF()) {
- return -1;
- } else {
- return Double.compare(node1.getH(), node2.getH());
- }
- }
- }
-
- /**
- * A node object used for the pathfinding widget.
- */
- private static class PathNode {
- /**
- * The node's x value.
- */
- private int x;
-
- /**
- * The node's y value.
- */
- private int y;
-
- /**
- * The node's g value.
- */
- private double g = Integer.MAX_VALUE;
-
- /**
- * The node's heuristic value.
- */
- private double h = Integer.MAX_VALUE;
-
- /**
- * The node's parent.
- */
- private PathNode parent;
-
- /**
- * Constructs a new path node.
- *
- * @param x the initial x value
- * @param y the initial y value
- */
- public PathNode(int x, int y) {
- this.x = x;
- this.y = y;
- }
-
- /**
- * Suppress default constructor.
- */
- private PathNode() {
- throw new IllegalMethodException("Cannot create PathNode with default constructor");
- }
-
- /**
- * Constructs a new path node.
- *
- * @param p the point to use as the initial x,y
- */
- public PathNode(Point p) {
- this(p.x, p.y);
- }
-
- /**
- * Returns the x of the node.
- *
- * @return the x of the node
- */
- public int getX() {
- return x;
- }
-
- /**
- * Sets the x of the node.
- *
- * @param x the x of the node
- */
- public void setX(int x) {
- this.x = x;
- }
-
- /**
- * Returns the y of the node.
- *
- * @return the y of the node
- */
- public int getY() {
- return y;
- }
-
- /**
- * Sets the y of the node.
- *
- * @param y the y of the node
- */
- public void setY(int y) {
- this.y = y;
- }
-
- /**
- * Returns the g cost of the node.
- *
- * @return the g cost of the node
- */
- public double getG() {
- return g;
- }
-
- /**
- * Sets the g cost of the node.
- *
- * @param g the g cost of the node
- */
- public void setG(double g) {
- this.g = g;
- }
-
- /**
- * Returns the h cost of the node.
- *
- * @return the h cost of the node
- */
- public double getH() {
- return h;
- }
-
- /**
- * Sets the h cost of the node.
- *
- * @param h the h cost of the node
- */
- public void setH(double h) {
- this.h = h;
- }
-
- /**
- * Returns the f cost of the node.
- *
- * @return the f cost of the node
- */
- public double getF() {
- return h + g;
- }
-
- /**
- * Returns the parent of the node.
- *
- * @return the parent of the node
- */
- public PathNode getParent() {
- return parent;
- }
-
- /**
- * Sets the parent of the node.
- *
- * @param parent the parent of the node
- */
- public void setParent(PathNode parent) {
- this.parent = parent;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object o) {
- if (o == null)
- return false;
- if (!(o instanceof PathNode other))
- return false;
- else {
- return other.getX() == x && other.getY() == y;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return x + ", " + y;
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/cyder/widgets/PerlinWidget.java b/src/main/java/cyder/widgets/PerlinWidget.java
deleted file mode 100644
index 1fe18a3b8..000000000
--- a/src/main/java/cyder/widgets/PerlinWidget.java
+++ /dev/null
@@ -1,820 +0,0 @@
-package cyder.widgets;
-
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.exceptions.IllegalMethodException;
-import cyder.layouts.CyderGridLayout;
-import cyder.layouts.CyderPartitionedLayout;
-import cyder.math.NumberUtil;
-import cyder.strings.CyderStrings;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.drag.CyderDragLabel;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.grid.GridNode;
-import cyder.ui.label.CyderLabel;
-import cyder.ui.pane.CyderPanel;
-import cyder.ui.selection.CyderSwitch;
-import cyder.ui.selection.CyderSwitchState;
-import cyder.ui.slider.CyderSliderUi;
-import cyder.ui.slider.ThumbShape;
-import cyder.utils.SimplexNoiseUtil;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.awt.event.ActionListener;
-import java.util.Random;
-
-/**
- * A visualizer for two dimensional perlin-noise and three-dimensional open simplex noise.
- */
-@Vanilla
-@CyderAuthor
-public final class PerlinWidget {
- /**
- * Suppress default constructor.
- */
- private PerlinWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * The button which starts the animation for the noise.
- */
- private static CyderButton animateButton;
-
- /**
- * The button which iterates to the next iteration of the noise.
- */
- private static CyderButton stepButton;
-
- /**
- * The button to regenerate the noise.
- */
- private static CyderButton regenerateButton;
-
- /**
- * The frame used for animation
- */
- private static CyderFrame perlinFrame;
-
- /**
- * The overridden label to paint the noise calculations on.
- */
- private static JLabel noiseLabel;
-
- /**
- * The minimum feature size for open simplex noise.
- */
- public static final double MINIMUM_FEATURE_SIZE = 24.0;
-
- /**
- * The default feature size for open simplex noise.
- */
- public static final double DEFAULT_FEATURE_SIZE = 24.0;
-
- /**
- * The maximum feature size for open simplex noise.
- */
- public static final double MAXIMUM_FEATURE_SIZE = MINIMUM_FEATURE_SIZE * 2.0;
-
- /**
- * The feature size for open simplex noise.
- */
- private static double featureSize = DEFAULT_FEATURE_SIZE;
-
- /**
- * The open simplex noise object.
- */
- private static SimplexNoiseUtil noise = new SimplexNoiseUtil(0);
-
- /**
- * The time step current at.
- */
- private static double timeStep;
-
- /**
- * The slider used to change the open simplex noise feature size.
- */
- private static JSlider featureSlider;
-
- /**
- * The dimension switch.
- */
- private static CyderSwitch dimensionSwitch;
-
- /**
- * The slider used to determine the speed of the animation.
- */
- private static JSlider speedSlider;
-
- /**
- * The default value for the speed slider.
- */
- private static int speedSliderValue = 400;
-
- /**
- * The maximum value for the speed slider.
- */
- private static final int speedSliderMaxValue = 500;
-
- /**
- * The minimum value for the speed slider.
- */
- private static final int speedSliderMinValue = 0;
-
- /**
- * The resolution of open simplex noise.
- */
- private static final int resolution = 600;
-
- /**
- * The node array to store the open simplex noise.
- */
- private static GridNode[][] noise3D;
-
- /**
- * The array to store the perlin noise.
- */
- private static float[] noise2D;
-
- /**
- * The random object used for randomizing the noise seeds.
- */
- private static final Random random = new Random();
-
- /**
- * The animation timer.
- */
- private static Timer timer;
-
- /**
- * The seeding value to use for open simplex noise.
- */
- private static float[][] instanceSeed;
-
- /**
- * The number of octaves for open simplex (iterations).
- */
- private static int octaves = 1;
-
- /**
- * The maximum number of octaves (iterations).
- */
- private static final int maxOctaves = 10;
-
- /**
- * Determines whether the frame has been requested to close or is already closed.
- */
- private static boolean closed = true;
-
- /**
- * The frame title string.
- */
- private static final String PERLIN = "Perlin Noise";
-
- /**
- * The stroke for drawing on the noise label.
- */
- private static final BasicStroke stroke = new BasicStroke(2);
-
- /**
- * The text for the step button.
- */
- private static final String STEP = "Step";
-
- /**
- * The time step increment.
- */
- private static final double timeStepIncrement = 0.1;
-
- /**
- * The stop string.
- */
- private static final String STOP = "Stop";
-
- /**
- * Half of the limit for 8-bit color values.
- */
- private static final float halfEightBitColorLimit = 127.5f;
-
- /**
- * The feature slider tooltip text.
- */
- private static final String THREE_D_FEATURE_SIZE = "3D Feature Size";
-
- /**
- * The animate string.
- */
- private static final String ANIMATE = "Animate";
-
- /**
- * The tooltip for the speed slider.
- */
- private static final String ANIMATE_TIMEOUT = "Animation Timeout";
-
- /**
- * The height of the sliders.
- */
- private static final int sliderHeight = 40;
-
- /**
- * The maximum feature slider value.
- */
- private static final int maxFeatureSliderValue = 1000;
-
- /**
- * The minimum feature slider value.
- */
- private static final int minFeatureSliderValue = 0;
-
- /**
- * The default feature slider value.
- */
- private static final int defaultFeatureSliderValue = (maxFeatureSliderValue - minFeatureSliderValue) / 2;
-
- /**
- * The grayscale multiplier value.
- */
- private static final int grayscaleMultiplier = 0x010101;
-
- /**
- * The length of the top line for 2D noise.
- */
- private static final int topLineLength = 2;
-
- /**
- * The length of the grass for 2D noise.
- */
- private static final int grassLength = 10;
-
- /**
- * The length of the dirt for 2D noise.
- */
- private static final int dirtLength = 20;
-
- /**
- * The text for the off state of the dimension switch button.
- */
- private static final String TWO_D = "2D";
-
- /**
- * The text for the on state of the dimension switch button.
- */
- private static final String THREE_D = "3D";
-
- /**
- * The text for the speed label.
- */
- private static final String SPEED = "Speed";
-
- /**
- * The text for the feature size label.
- */
- private static final String FEATURE_SIZE = "Feature size";
-
- /**
- * The padding between the frame and the start of components.
- */
- private static final int framePadding = 25;
-
- /**
- * The width of the frame.
- */
- private static final int frameWidth = resolution + 2 * framePadding;
-
- /**
- * The height of the bottom control components.
- */
- private static final int interactionComponentsHeight = 240;
-
- /**
- * The frame height.
- */
- private static final int frameHeight = resolution + 2 * framePadding
- + CyderDragLabel.DEFAULT_HEIGHT + interactionComponentsHeight;
-
- /**
- * The regenerate button text.
- */
- private static final String REGENERATE = "Regenerate";
-
- /**
- * The size of the dimension switch button
- */
- private static final Dimension dimensionSwitchSize = new Dimension(180, 55);
-
- /**
- * The size of the slider labels.
- */
- private static final Dimension sliderLabelSize = new Dimension(200, 40);
-
- /**
- * The size of the buttons.
- */
- private static final Dimension buttonSize = new Dimension(180, 40);
-
- /**
- * The length of the noise label border.
- */
- private static final int noiseLabelBorderLength = 5;
-
- /**
- * Shows the perlin noise widget.
- */
- @Widget(triggers = {"perlin", "noise"}, description = "Perlin noise visualizer/open simplex noise visualizer")
- public static void showGui() {
- UiUtil.closeIfOpen(perlinFrame);
-
- closed = false;
- timeStep = 0;
- octaves = 1;
-
- instanceSeed = new float[resolution][resolution];
-
- generateNewSeed();
-
- initializeNoise();
-
- timer = new Timer(speedSliderMaxValue - speedSliderValue, animationAction);
-
- perlinFrame = new CyderFrame(new CyderFrame.Builder().setWidth(frameWidth).setHeight(frameHeight)) {
- @Override
- public void repaint() {
- if (twoDimensionalMode()) {
- super.repaint();
- }
- }
- };
- perlinFrame.setTitle(PERLIN);
- perlinFrame.addPreCloseAction(PerlinWidget::preCloseActions);
-
- noiseLabel = new JLabel() {
- @Override
- public void paint(Graphics g) {
- if (closed) return;
- super.paint(g);
-
- Graphics2D g2d = (Graphics2D) g;
- g2d.setColor(Color.darkGray);
- g2d.setStroke(stroke);
-
- if (twoDimensionalMode()) {
- draw2DNoise(g2d);
- } else {
- draw3DNoise(g2d);
- }
- }
- };
- noiseLabel.setBounds(noiseLabelBorderLength, noiseLabelBorderLength, resolution, resolution);
-
- JLabel noiseParentLabel = new JLabel();
- noiseParentLabel.setSize(resolution + 2 * noiseLabelBorderLength,
- resolution + 2 * noiseLabelBorderLength);
- noiseParentLabel.setBorder(new LineBorder(CyderColors.navy, noiseLabelBorderLength));
- noiseParentLabel.add(noiseLabel);
-
- CyderLabel animateLabel = new CyderLabel(ANIMATE);
- animateLabel.setSize(100, 20);
-
- animateButton = new CyderButton(ANIMATE);
- animateButton.addActionListener(e -> generate());
- animateButton.setToolTipText("Animate Perlin Noise");
- animateButton.setSize(buttonSize);
-
- stepButton = new CyderButton(STEP);
- stepButton.addActionListener(e -> nextIteration());
- stepButton.setToolTipText("Increments the octave and displayed the revalidated noise");
- stepButton.setSize(buttonSize);
-
- regenerateButton = new CyderButton(REGENERATE);
- regenerateButton.addActionListener(e -> regenerateButtonAction());
- regenerateButton.setToolTipText("Regenerates the noise");
- regenerateButton.setSize(buttonSize);
-
- speedSlider = new JSlider(JSlider.HORIZONTAL, speedSliderMinValue, speedSliderMaxValue, speedSliderValue);
-
- CyderSliderUi speedSliderUi = new CyderSliderUi(speedSlider);
- speedSliderUi.setThumbRadius(25);
- speedSliderUi.setThumbShape(ThumbShape.CIRCLE);
- speedSliderUi.setThumbFillColor(Color.black);
- speedSliderUi.setThumbOutlineColor(CyderColors.navy);
- speedSliderUi.setRightThumbColor(CyderColors.regularBlue);
- speedSliderUi.setLeftThumbColor(CyderColors.regularPink);
- speedSliderUi.setTrackStroke(new BasicStroke(3.0f));
-
- speedSlider.setUI(speedSliderUi);
- speedSlider.setSize(resolution - 2 * framePadding, sliderHeight);
- speedSlider.setPaintTicks(false);
- speedSlider.setPaintLabels(false);
- speedSlider.setVisible(true);
- speedSlider.setValue(speedSliderValue);
- speedSlider.addChangeListener(e -> speedSliderChangeAction());
- speedSlider.setOpaque(false);
- speedSlider.setToolTipText(ANIMATE_TIMEOUT);
- speedSlider.setFocusable(false);
- speedSlider.repaint();
-
- featureSlider = new JSlider(JSlider.HORIZONTAL, minFeatureSliderValue,
- maxFeatureSliderValue, defaultFeatureSliderValue);
-
- CyderSliderUi featureSliderUi = new CyderSliderUi(featureSlider);
- featureSliderUi.setThumbRadius(25);
- featureSliderUi.setThumbShape(ThumbShape.CIRCLE);
- featureSliderUi.setThumbFillColor(Color.black);
- featureSliderUi.setThumbOutlineColor(CyderColors.navy);
- featureSliderUi.setRightThumbColor(CyderColors.regularBlue);
- featureSliderUi.setLeftThumbColor(CyderColors.regularPink);
- featureSliderUi.setTrackStroke(new BasicStroke(3.0f));
-
- featureSlider.setUI(featureSliderUi);
- featureSlider.setSize(resolution - 2 * framePadding, sliderHeight);
- featureSlider.setPaintTicks(false);
- featureSlider.setPaintLabels(false);
- featureSlider.setVisible(true);
- featureSlider.setValue(defaultFeatureSliderValue);
- featureSlider.addChangeListener(e -> featureSliderChangeAction());
- featureSlider.setOpaque(false);
- featureSlider.setToolTipText(THREE_D_FEATURE_SIZE);
- featureSlider.setFocusable(false);
- featureSlider.repaint();
-
- dimensionSwitch = new CyderSwitch(dimensionSwitchSize, CyderSwitchState.OFF);
- dimensionSwitch.setButtonPercent(50);
- dimensionSwitch.setSize(dimensionSwitchSize);
- dimensionSwitch.setOffText(TWO_D);
- dimensionSwitch.setOnText(THREE_D);
- dimensionSwitch.getSwitchButton().addActionListener(e -> dimensionSwitchButtonAction());
-
- CyderPartitionedLayout partitionedLayout = new CyderPartitionedLayout();
- partitionedLayout.spacer(2);
- partitionedLayout.addComponent(noiseParentLabel, 70);
-
- CyderLabel speedSliderLabel = new CyderLabel(SPEED);
- speedSliderLabel.setSize(sliderLabelSize);
- CyderLabel featureSliderLabel = new CyderLabel(FEATURE_SIZE);
- featureSliderLabel.setSize(sliderLabelSize);
-
- partitionedLayout.addComponent(speedSliderLabel, 4);
- partitionedLayout.addComponent(speedSlider, 2);
- partitionedLayout.addComponent(featureSliderLabel, 4);
- partitionedLayout.addComponent(featureSlider, 2);
-
- CyderGridLayout gridLayout = new CyderGridLayout(2, 2);
- gridLayout.addComponent(animateButton);
- gridLayout.addComponent(stepButton);
- gridLayout.addComponent(regenerateButton);
- gridLayout.addComponent(dimensionSwitch);
- CyderPanel gridPanel = new CyderPanel(gridLayout);
- gridPanel.setSize(600, 120);
-
- partitionedLayout.spacer(6);
- partitionedLayout.addComponent(gridPanel, 5);
- partitionedLayout.spacer(4);
-
- perlinFrame.setCyderLayout(partitionedLayout);
- perlinFrame.finalizeAndShow();
- }
-
- /**
- * The actions to invoke when the dimension switch button is pressed.
- */
- @ForReadability
- private static void dimensionSwitchButtonAction() {
- regenerateButtonAction();
- perlinFrame.repaint();
- }
-
- /**
- * Returns whether the current perlin nose mode is 2D.
- *
- * @return whether the current perlin nose mode is 2D
- */
- @ForReadability
- private static boolean twoDimensionalMode() {
- return dimensionSwitch.getState().equals(CyderSwitchState.OFF);
- }
-
- /**
- * The actions to invoke when the regenerate button is clicked.
- */
- private static void regenerateButtonAction() {
- if (twoDimensionalMode()) {
- if (timer.isRunning()) {
- timer.stop();
- unlockUI();
- }
-
- generateNewSeed();
- octaves = 1;
- noise2D = generate2DNoise(instanceSeed[0], octaves);
- } else {
- timeStep = 0;
-
- noise = new SimplexNoiseUtil(NumberUtil.generateRandomInt(1000));
- for (int y = 0 ; y < resolution ; y++) {
- for (int x = 0 ; x < resolution ; x++) {
- double value = noise.eval(x / featureSize, y / featureSize, timeStep);
- noise3D[x][y].setColor(generateGrayscaleColor(value));
- noise3D[x][y].setX(x);
- noise3D[x][y].setY(y);
- }
- }
- }
-
- noiseLabel.repaint();
- }
-
- /**
- * Initializes the 2D and 3D noise.
- */
- @ForReadability
- private static void initializeNoise() {
- noise2D = new float[resolution];
- noise2D = generate2DNoise(instanceSeed[0], octaves);
-
- noise3D = new GridNode[resolution][resolution];
- for (int x = 0 ; x < resolution ; x++) {
- for (int y = 0 ; y < resolution ; y++) {
- noise3D[x][y] = new GridNode(x, y);
- }
- }
- }
-
- /**
- * The actions to invoke on a feature slider value change.
- */
- @ForReadability
- private static void featureSliderChangeAction() {
- featureSize = (featureSlider.getValue() / (float) maxFeatureSliderValue)
- * (MAXIMUM_FEATURE_SIZE - MINIMUM_FEATURE_SIZE) + MINIMUM_FEATURE_SIZE;
-
- if (!twoDimensionalMode() && !timer.isRunning()) {
- for (int y = 0 ; y < resolution ; y++) {
- for (int x = 0 ; x < resolution ; x++) {
- double value = noise.eval(x / featureSize, y / featureSize, timeStep);
- Color color = generateGrayscaleColor(value);
-
- GridNode ref = noise3D[x][y];
-
- ref.setColor(color);
- ref.setX(x);
- ref.setY(y);
- }
- }
-
- noiseLabel.repaint();
- }
- }
-
- /**
- * The pre close action to invoke when the frame's dispose function has been called.
- */
- @ForReadability
- private static void preCloseActions() {
- noise2D = null;
- noise3D = null;
- closed = true;
-
- stopTimerIfRunning();
- }
-
- /**
- * The actions to invoke on a speed slider value change.
- */
- @ForReadability
- private static void speedSliderChangeAction() {
- speedSliderValue = speedSlider.getValue();
- timer.setDelay(speedSliderMaxValue - speedSliderValue);
- }
-
- /**
- * Draws two dimension noise on the noise label.
- *
- * @param g2d the 2D graphics object
- */
- @ForReadability
- private static void draw2DNoise(Graphics2D g2d) {
- int width = 2;
-
- for (int x = 0 ; x < resolution - 1 ; x++) {
- float y = (float) ((noise2D[x] * resolution / 2.0) + resolution / 2.0);
- int minY = (int) y;
- int lenDown = 0;
-
- // Draw top line
- g2d.setColor(Color.black);
- g2d.fillRect(x, minY, width, topLineLength);
- lenDown += topLineLength;
-
- // Draw grass
- g2d.setColor(CyderColors.regularGreen);
- g2d.fillRect(x, minY + lenDown, width, grassLength);
- lenDown += grassLength;
-
- // Draw dirt
- g2d.setColor(CyderColors.brownDirt);
- g2d.fillRect(x, minY + lenDown, width, dirtLength);
- lenDown += dirtLength;
-
- // Draw stone
- int stoneLength = resolution - (minY + lenDown);
- g2d.setColor(Color.darkGray);
- g2d.fillRect(x, minY + lenDown, width, stoneLength);
- }
- }
-
- /**
- * Draws three dimensional noise on the noise label.
- *
- * @param g2d the 2D graphics object
- */
- @ForReadability
- private static void draw3DNoise(Graphics2D g2d) {
- int len = 1;
-
- for (int i = 0 ; i < resolution ; i++) {
- for (int j = 0 ; j < resolution ; j++) {
- g2d.setColor(noise3D[i][j].getColor());
- g2d.fillRect(i, j, len, len);
- }
- }
- }
-
- /**
- * Stops the timer if running.
- */
- @ForReadability
- private static void stopTimerIfRunning() {
- if (timer != null && timer.isRunning()) {
- timer.stop();
- }
- }
-
- /**
- * Generates new noise based on the current random seed.
- */
- private static void generate() {
- if (closed) return;
-
- if (timer.isRunning()) {
- timer.stop();
- animateButton.setText(ANIMATE);
- unlockUI();
- } else {
- lockUI();
- animateButton.setText(STOP);
- timer.start();
- }
- }
-
- /**
- * Generates the new iteration of noise from the current noise.
- */
- private static void nextIteration() {
- if (closed) return;
-
- if (twoDimensionalMode()) {
- if (timer != null && timer.isRunning()) return;
-
- octaves++;
- if (octaves == maxOctaves) {
- octaves = 1;
- }
-
- noise2D = generate2DNoise(instanceSeed[0], octaves);
- } else {
- //serves no purpose during an animation
- if (timer != null && timer.isRunning()) return;
-
- timeStep += timeStepIncrement;
-
- for (int y = 0 ; y < resolution ; y++) {
- for (int x = 0 ; x < resolution ; x++) {
- if (closed) return;
-
- double value = noise.eval(x / featureSize, y / featureSize, timeStep);
- noise3D[x][y].setColor(generateGrayscaleColor(value));
- noise3D[x][y].setX(x);
- noise3D[x][y].setY(y);
- }
- }
- }
-
- noiseLabel.repaint();
- }
-
- /**
- * Generates perlin noise based on common algorithm implementation.
- *
- * @param fSeed the seed value
- * @param nOctaves the number of iterations to perform the algorithm on
- * @return 2D perlin noise representation (values are between 0 and 1)
- */
- private static float[] generate2DNoise(float[] fSeed, int nOctaves) {
- float[] ret = new float[resolution];
-
- for (int x = 0 ; x < resolution ; x++) {
- float fNoise = 0.0f;
- float fScale = 1.0f;
- float fScaleAcc = 0.0f;
-
- for (int octave = 0 ; octave < nOctaves ; octave++) {
- /*
- Assuming octave is a power of two
-
- assert (octave & (octave - 1)) == 0;
- */
- int nPitch = resolution >> octave;
- int nSample1 = (x / nPitch) * nPitch;
- int nSample2 = (nSample1 + nPitch) % resolution;
-
- float fBlend = (float) (x - nSample1) / (float) nPitch;
- float fSample = (1.0f - fBlend) * fSeed[nSample1] + fBlend * fSeed[nSample2];
- fNoise += fSample * fScale;
- fScaleAcc += fScale;
- fScale = fScale / 2.0f;
- }
-
- ret[x] = fNoise / fScaleAcc;
- }
-
- return ret;
- }
-
- /**
- * The function for the timer to invoke when noise animation is enabled.
- */
- private static final ActionListener animationAction = evt -> {
- if (closed) return;
-
- octaves++;
-
- if (octaves == maxOctaves) {
- octaves = 1;
- generateNewSeed();
- }
-
- if (twoDimensionalMode()) {
- noise2D = generate2DNoise(instanceSeed[0], octaves);
- } else {
- timeStep += timeStepIncrement;
-
- for (int y = 0 ; y < resolution ; y++) {
- for (int x = 0 ; x < resolution ; x++) {
- if (closed) return;
-
- double value = noise.eval(x / featureSize, y / featureSize, timeStep);
- noise3D[x][y].setColor(generateGrayscaleColor(value));
- noise3D[x][y].setX(x);
- noise3D[x][y].setY(y);
- }
- }
- }
-
- noiseLabel.repaint();
- };
-
- @ForReadability
- private static void generateNewSeed() {
- for (int i = 0 ; i < resolution ; i++) {
- for (int j = 0 ; j < resolution ; j++) {
- instanceSeed[i][j] = random.nextFloat();
- }
- }
- }
-
- /**
- * Generates a grayscale color from the double value.
- *
- * @param value the value to map to a grayscale color
- * @return a grayscale color unique to the double provided
- */
- private static Color generateGrayscaleColor(double value) {
- return new Color(grayscaleMultiplier * (int) ((value + 1) * halfEightBitColorLimit));
- }
-
- /**
- * Locks the perlin UI.
- */
- private static void lockUI() {
- regenerateButton.setEnabled(false);
- stepButton.setEnabled(false);
- dimensionSwitch.setEnabled(false);
- featureSlider.setEnabled(false);
- }
-
- /**
- * Unlocks the perlin UI.
- */
- private static void unlockUI() {
- regenerateButton.setEnabled(true);
- stepButton.setEnabled(true);
- dimensionSwitch.setEnabled(true);
- featureSlider.setEnabled(true);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/cyder/widgets/PhoneWidget.java b/src/main/java/cyder/widgets/PhoneWidget.java
deleted file mode 100644
index 5e9c2d1ea..000000000
--- a/src/main/java/cyder/widgets/PhoneWidget.java
+++ /dev/null
@@ -1,389 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.base.Preconditions;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.audio.GeneralAudioPlayer;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderModernButton;
-import cyder.ui.button.ThemeBuilder;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.utils.StaticUtil;
-
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.File;
-import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static cyder.strings.CyderStrings.*;
-
-/**
- * A phone number dialing widget.
- */
-@Vanilla
-@CyderAuthor
-public final class PhoneWidget {
- /**
- * The dialing string.
- */
- private static final String DIALING = "Dialing: ";
-
- /**
- * The width of the widget frame.
- */
- private static final int FRAME_WIDTH = 320;
-
- /**
- * The height of the widget frame.
- */
- private static final int FRAME_HEIGHT = 500;
-
- /**
- * The string for the back button.
- */
- private static final String backText = "<<";
-
- /**
- * The string used for the call button.
- */
- private static final String CALL = "Call";
-
- /**
- * A regex for targeting anything that is not a digit.
- */
- private static final String NON_DIGITS_REGEX = "[^\\d.]";
-
- /**
- * The widget title.
- */
- private static final String TITLE = "Phone";
-
- /**
- * The button theme.
- */
- private static final ThemeBuilder theme = new ThemeBuilder()
- .setFont(CyderFonts.SEGOE_30)
- .setBackgroundColor(CyderColors.regularOrange)
- .setBorderColor(CyderColors.navy)
- .setBorderLength(5);
-
- /**
- * The field numbers are stored in.
- */
- private static CyderTextField numberField;
-
- /**
- * The current number.
- */
- private static String currentPhoneNumber;
-
- /**
- * The widget frame.
- */
- private static CyderFrame phoneFrame;
-
- /**
- * Suppress default constructor.
- */
- private PhoneWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- /**
- * Special numbers which when dialed trigger an audio file to play, generally with the same name as the number.
- */
- private enum SpecialNumber {
- /**
- * The 1800 number, plays 1800 by Logic.
- */
- SUICIDE_HOTLINE(18002738255L, StaticUtil.getStaticResource("1800.mp3")),
-
- /**
- * The 223 number, plays 223 by YNW Melly
- */
- TWO_TWO_THREE(223L, StaticUtil.getStaticResource("223.mp3"));
-
- /**
- * The number dialed to trigger this.
- */
- private final long number;
-
- /**
- * The audio file to play.
- */
- private final File audioFile;
-
- SpecialNumber(long number, File audioFile) {
- this.number = number;
- this.audioFile = audioFile;
- }
-
- /**
- * Returns the number dialed to trigger this.
- *
- * @return the number dialed to trigger this
- */
- public long getNumber() {
- return number;
- }
-
- /**
- * Returns the audio file to play.
- *
- * @return the audio file to play
- */
- public File getAudioFile() {
- return audioFile;
- }
-
- /**
- * Plays this audio file using the general audio player.
- */
- public void play() {
- GeneralAudioPlayer.playAudio(audioFile);
- }
-
- /**
- * Ends all special audio files if playing.
- */
- public static void endAllAudio() {
- Arrays.stream(values()).forEach(specialNumber ->
- GeneralAudioPlayer.stopAudio(specialNumber.getAudioFile()));
- }
- }
-
- @Widget(triggers = "phone", description = "A phone emulating widget")
- public static void showGui() {
- UiUtil.closeIfOpen(phoneFrame);
-
- phoneFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(TITLE)
- .build();
- phoneFrame.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- SpecialNumber.endAllAudio();
- }
- });
-
- numberField = new CyderTextField();
- numberField.setText(hash);
- numberField.setEditable(false);
- numberField.setFont(CyderFonts.SEGOE_20);
- numberField.setBounds(20, 40, 320 - 40, 40);
- phoneFrame.getContentPane().add(numberField);
-
- currentPhoneNumber = "";
-
- CyderModernButton zero = new CyderModernButton("0");
- zero.setBounds(120, 400, 80, 80);
- phoneFrame.getContentPane().add(zero);
- zero.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + zero.getText();
- refreshFieldText();
- });
- zero.setTheme(theme);
-
- CyderModernButton one = new CyderModernButton("1");
- one.setBounds(20, 100, 80, 80);
- phoneFrame.getContentPane().add(one);
- one.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + one.getText();
- refreshFieldText();
- });
- one.setTheme(theme);
-
- CyderModernButton two = new CyderModernButton("2");
- two.setBounds(120, 100, 80, 80);
- phoneFrame.getContentPane().add(two);
- two.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + two.getText();
- refreshFieldText();
- });
- two.setTheme(theme);
-
- CyderModernButton three = new CyderModernButton("3");
- three.setBounds(220, 100, 80, 80);
- phoneFrame.getContentPane().add(three);
- three.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + three.getText();
- refreshFieldText();
- });
- three.setTheme(theme);
-
- CyderModernButton four = new CyderModernButton("4");
- four.setBounds(20, 200, 80, 80);
- phoneFrame.getContentPane().add(four);
- four.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + four.getText();
- refreshFieldText();
- });
- four.setTheme(theme);
-
- CyderModernButton five = new CyderModernButton("5");
- five.setBounds(120, 200, 80, 80);
- phoneFrame.getContentPane().add(five);
- five.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + five.getText();
- refreshFieldText();
- });
- five.setTheme(theme);
-
- CyderModernButton six = new CyderModernButton("6");
- six.setBounds(220, 200, 80, 80);
- phoneFrame.getContentPane().add(six);
- six.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + six.getText();
- refreshFieldText();
- });
- six.setTheme(theme);
-
- CyderModernButton seven = new CyderModernButton("7");
- seven.setBounds(20, 300, 80, 80);
- phoneFrame.getContentPane().add(seven);
- seven.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + seven.getText();
- refreshFieldText();
- });
- seven.setTheme(theme);
-
- CyderModernButton eight = new CyderModernButton("8");
- eight.setBounds(120, 300, 80, 80);
- phoneFrame.getContentPane().add(eight);
- eight.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + eight.getText();
- refreshFieldText();
- });
- eight.setTheme(theme);
-
- CyderModernButton nine = new CyderModernButton("9");
- nine.setBounds(220, 300, 80, 80);
- phoneFrame.getContentPane().add(nine);
- nine.addClickRunnable(() -> {
- currentPhoneNumber = currentPhoneNumber + nine.getText();
- refreshFieldText();
- });
- nine.setTheme(theme);
-
- CyderModernButton back = new CyderModernButton(backText);
- back.setBounds(20, 400, 80, 80);
- phoneFrame.getContentPane().add(back);
- back.addClickRunnable(() -> {
- if (!currentPhoneNumber.isEmpty()) {
- currentPhoneNumber = currentPhoneNumber.substring(0, currentPhoneNumber.length() - 1);
- refreshFieldText();
- }
- });
- back.setTheme(theme);
-
- CyderModernButton dialNumber = new CyderModernButton(CALL);
- dialNumber.setBounds(220, 400, 80, 80);
- phoneFrame.getContentPane().add(dialNumber);
- dialNumber.addClickRunnable(PhoneWidget::dialNumberAction);
- dialNumber.setTheme(theme);
-
- phoneFrame.finalizeAndShow();
- }
-
- /**
- * The actions to take when the dial number button is pressed.
- */
- @ForReadability
- private static void dialNumberAction() {
- if (currentPhoneNumber.isEmpty()) return;
- if (checkForNumbers()) return;
-
- phoneFrame.toast(DIALING + numberField.getText());
- refreshFieldText();
- }
-
- /**
- * Refreshes the field text based on the current phone number.
- */
- private static void refreshFieldText() {
- numberField.setText(formatNumber(currentPhoneNumber));
- }
-
- /**
- * Checks the {@link SpecialNumber}s for a special number.
- *
- * @return whether a special number was found and the runnable invoked
- */
- @ForReadability
- private static boolean checkForNumbers() {
- AtomicBoolean ret = new AtomicBoolean();
-
- long dialedNumber = Long.parseLong(StringUtil.getTrimmedText(numberField.getText())
- .replaceAll(NON_DIGITS_REGEX, ""));
- Arrays.stream(SpecialNumber.values()).filter(specialNumber -> specialNumber.getNumber() == dialedNumber)
- .findFirst().ifPresent(specialNumber -> {
- specialNumber.play();
- ret.set(true);
- currentPhoneNumber = "";
- refreshFieldText();
- });
-
- return ret.get();
- }
-
- /**
- * Returns the number formatted based on the current number
- * of digits contained in the phone number.
- *
- * @param num the current phone number
- * @return the phone number formatted
- */
- private static String formatNumber(String num) {
- Preconditions.checkNotNull(num);
-
- if (num.isEmpty())
-
- num = num.replaceAll(NON_DIGITS_REGEX, "");
- int length = num.length();
-
- if (length == 0) {
- return hash;
- } else if (length < 5) {
- return num;
- } else if (length == 5) {
- return num.charAt(0) + dash + num.substring(1, 5);
- } else if (length == 6) {
- return num.substring(0, 2) + dash + num.substring(2, 6);
- } else if (length == 7) {
- return num.substring(0, 3) + dash + num.substring(3, 7);
- } else if (length == 8) {
- return openingParenthesis + num.charAt(0) + closingParenthesis + space
- + num.substring(1, 4) + space + num.substring(4, 8);
- } else if (length == 9) {
- return openingParenthesis + num.substring(0, 2) + closingParenthesis + space
- + num.substring(2, 5) + space + num.substring(5, 9);
- } else if (length == 10) {
- return openingParenthesis + num.substring(0, 3) + closingParenthesis + space
- + num.substring(3, 6) + space + num.substring(6, 10);
- } else {
- if (length > 15) {
- currentPhoneNumber = numberField.getText();
- return numberField.getText();
- }
-
- String leadingDigits = num.substring(0, length - 10);
- int offset = leadingDigits.length();
-
- return (leadingDigits + space + openingParenthesis + num.substring(offset, 3 + offset) +
- closingParenthesis +
- space
- + num.substring(3 + offset, 6 + offset) + space + num.substring(6 + offset, length));
- }
- }
-}
diff --git a/src/main/java/cyder/widgets/PizzaWidget.java b/src/main/java/cyder/widgets/PizzaWidget.java
deleted file mode 100644
index 47ef033f8..000000000
--- a/src/main/java/cyder/widgets/PizzaWidget.java
+++ /dev/null
@@ -1,547 +0,0 @@
-package cyder.widgets;
-
-import com.google.common.collect.ImmutableList;
-import cyder.annotations.CyderAuthor;
-import cyder.annotations.ForReadability;
-import cyder.annotations.Vanilla;
-import cyder.annotations.Widget;
-import cyder.constants.CyderColors;
-import cyder.constants.CyderFonts;
-import cyder.constants.HtmlTags;
-import cyder.exceptions.IllegalMethodException;
-import cyder.strings.CyderStrings;
-import cyder.strings.StringUtil;
-import cyder.ui.UiUtil;
-import cyder.ui.button.CyderButton;
-import cyder.ui.field.CyderTextField;
-import cyder.ui.frame.CyderFrame;
-import cyder.ui.list.CyderScrollList;
-import cyder.ui.pane.CyderScrollPane;
-import cyder.ui.selection.CyderCheckbox;
-import cyder.ui.selection.CyderCheckboxGroup;
-
-import javax.swing.*;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-import java.util.ArrayList;
-import java.util.Optional;
-
-/**
- * A widget for ordering pizza.
- */
-@Vanilla
-@CyderAuthor
-public final class PizzaWidget {
- /**
- * The widget frame.
- */
- private static CyderFrame pizzaFrame;
-
- /**
- * The customer name field.
- */
- private static CyderTextField nameField;
-
- /**
- * The checkbox group for the pizza size checkboxes.
- */
- private static CyderCheckboxGroup sizeGroup;
-
- /**
- * The small pizza checkbox.
- */
- private static CyderCheckbox smallCheckbox;
-
- /**
- * The medium pizza checkbox.
- */
- private static CyderCheckbox mediumCheckbox;
-
- /**
- * The large pizza checkbox.
- */
- private static CyderCheckbox largeCheckbox;
-
- /**
- * The pizza toppings scroll list.
- */
- private static CyderScrollList pizzaToppingsScroll;
-
- /**
- * The crust type scroll list.
- */
- private static CyderScrollList crustTypeScroll;
-
- /**
- * The comments area.
- */
- private static JTextArea orderComments;
-
- /**
- * The bread sticks checkbox.
- */
- private static CyderCheckbox breadSticks;
-
- /**
- * The salad checkbox.
- */
- private static CyderCheckbox salad;
-
- /**
- * The soda checkbox.
- */
- private static CyderCheckbox soda;
-
- /**
- * The title of the widget frame.
- */
- private static final String FRAME_TITLE = "Pizza";
-
- /**
- * The width of the widget frame.
- */
- private static final int FRAME_WIDTH = 600;
-
- /**
- * The height of the widget frame.
- */
- private static final int FRAME_HEIGHT = 800;
-
- /**
- * The text of the name label.
- */
- private static final String NAME = "Name:";
-
- /**
- * The text of the size label.
- */
- private static final String SIZE = "Size:";
-
- /**
- * The small text.
- */
- private static final String SMALL = "Small";
-
- /**
- * The medium text.
- */
- private static final String MEDIUM = "Medium";
-
- /**
- * The large text.
- */
- private static final String LARGE = "Large";
-
- /**
- * The crust type label text.
- */
- private static final String CRUST_TYPE = "Crust Type";
-
- /**
- * The toppings label text.
- */
- private static final String TOPPINGS = "Toppings";
-
- /**
- * The rest button text.
- */
- private static final String RESET = "Reset";
-
- /**
- * The place order button text.
- */
- private static final String PLACE_ORDER = "Place Order";
-
- /**
- * The extras label text.
- */
- private static final String EXTRAS = "Extras:";
-
- /**
- * The bread sticks string.
- */
- private static final String BREAD_STICKS = "Bread Sticks";
-
- /**
- * The salad string.
- */
- private static final String SALAD = "Salad";
-
- /**
- * The soda string.
- */
- private static final String SODA = "Soda";
-
- /**
- * The order comments string.
- */
- private static final String ORDER_COMMENTS = "Order Comments";
-
- /**
- * The value for an empty topping list.
- */
- private static final String PLAIN = "Plain";
-
- /**
- * The default crust type.
- */
- private static final String THIN = "Thin";
-
- /**
- * The text for if no order comments are specified.
- */
- private static final String NO_COMMENTS = "No comments";
-
- /**
- * The title of the order confirmation inform pane.
- */
- private static final String informTitle = "Order";
-
- /**
- * The text for if no extras are specified.
- */
- private static final String NO_EXTRAS = "No extras";
-
- /**
- * The possible values for pizza crusts.
- */
- private static final ImmutableList crustTypes = ImmutableList.of(
- "Thin",
- "Thick",
- "Deep dish",
- "Classic",
- "Tavern",
- "Seasonal");
-
- /**
- * The possible values for pizza toppings.
- */
- private static final ImmutableList pizzaToppings = ImmutableList.of(
- "Pepperoni",
- "Sausage",
- "Green peppers",
- "Onions",
- "Tomatoes",
- "Anchovies",
- "Bacon",
- "Chicken",
- "Beef",
- "Olives",
- "Mushrooms");
-
- /**
- * The length of the pizza topping scroll (width and height).
- */
- private static final int pizzaToppingsScrollLength = 200;
-
- /**
- * The width of the crust type scroll.
- */
- private static final int crustScrollWidth = 160;
-
- /**
- * The height of the crust type scroll.
- */
- private static final int crustScrollHeight = 200;
-
- /**
- * Suppress default constructor.
- */
- private PizzaWidget() {
- throw new IllegalMethodException(CyderStrings.ATTEMPTED_INSTANTIATION);
- }
-
- @Widget(triggers = "pizza", description = "A fake pizza ordering widget")
- public static void showGui() {
- UiUtil.closeIfOpen(pizzaFrame);
-
- pizzaFrame = new CyderFrame.Builder()
- .setWidth(FRAME_WIDTH)
- .setHeight(FRAME_HEIGHT)
- .setTitle(FRAME_TITLE)
- .build();
-
- JLabel nameLabel = new JLabel(NAME);
- nameLabel.setFont(CyderFonts.SEGOE_20);
- nameLabel.setForeground(CyderColors.navy);
- nameLabel.setBounds(40, 45, 100, 30);
- pizzaFrame.getContentPane().add(nameLabel);
-
- nameField = new CyderTextField();
- nameField.setHorizontalAlignment(JTextField.CENTER);
- nameField.setAutoCapitalization(true);
- nameField.setBackground(Color.white);
- nameField.setBounds(140, 40, 400, 40);
- pizzaFrame.getContentPane().add(nameField);
-
- JLabel sizeLabel = new JLabel(SIZE);
- sizeLabel.setFont(CyderFonts.SEGOE_20);
- sizeLabel.setForeground(CyderColors.navy);
- sizeLabel.setBounds(40, 140, 50, 30);
- pizzaFrame.getContentPane().add(sizeLabel);
-
- JLabel smallLabel = new JLabel(SMALL);
- smallLabel.setFont(CyderFonts.SEGOE_20);
- smallLabel.setForeground(CyderColors.navy);
- smallLabel.setBounds(180, 100, 100, 30);
- pizzaFrame.getContentPane().add(smallLabel);
-
- JLabel mediumLabel = new JLabel(MEDIUM);
- mediumLabel.setFont(CyderFonts.SEGOE_20);
- mediumLabel.setForeground(CyderColors.navy);
- mediumLabel.setBounds(285, 100, 100, 30);
- pizzaFrame.getContentPane().add(mediumLabel);
-
- JLabel largeLabel = new JLabel(LARGE);
- largeLabel.setFont(CyderFonts.SEGOE_20);
- largeLabel.setForeground(CyderColors.navy);
- largeLabel.setBounds(420, 100, 100, 30);
- pizzaFrame.getContentPane().add(largeLabel);
-
- sizeGroup = new CyderCheckboxGroup();
-
- smallCheckbox = new CyderCheckbox();
- smallCheckbox.setHorizontalAlignment(SwingConstants.CENTER);
- smallCheckbox.setNotChecked();
- smallCheckbox.setBounds(185, 135, 50, 50);
- pizzaFrame.getContentPane().add(smallCheckbox);
- sizeGroup.addCheckbox(smallCheckbox);
-
- mediumCheckbox = new CyderCheckbox();
- mediumCheckbox.setHorizontalAlignment(SwingConstants.CENTER);
- mediumCheckbox.setBounds(305, 135, 50, 50);
- pizzaFrame.getContentPane().add(mediumCheckbox);
- sizeGroup.addCheckbox(mediumCheckbox);
-
- largeCheckbox = new CyderCheckbox();
- largeCheckbox.setHorizontalAlignment(SwingConstants.CENTER);
- largeCheckbox.setNotChecked();
- largeCheckbox.setBounds(425, 135, 50, 50);
- pizzaFrame.getContentPane().add(largeCheckbox);
- sizeGroup.addCheckbox(largeCheckbox);
-
- JLabel crustLabel = new JLabel(CRUST_TYPE);
- crustLabel.setFont(CyderFonts.SEGOE_20);
- crustLabel.setForeground(CyderColors.navy);
- crustLabel.setBounds(90, 210, 130, 30);
- pizzaFrame.getContentPane().add(crustLabel);
-
- JLabel Toppings = new JLabel(TOPPINGS);
- Toppings.setFont(CyderFonts.SEGOE_20);
- Toppings.setForeground(CyderColors.navy);
- Toppings.setBounds(370, 210, 130, 30);
- pizzaFrame.getContentPane().add(Toppings);
-
- crustTypeScroll = new CyderScrollList(crustScrollWidth, crustScrollHeight,
- CyderScrollList.SelectionPolicy.SINGLE);
- crustTypes.forEach(crustType -> crustTypeScroll.addElement(crustType));
-
- JLabel crustTypeLabel = crustTypeScroll.generateScrollList();
- crustTypeLabel.setBounds(80, 250, 160, 200);
- pizzaFrame.getContentPane().add(crustTypeLabel);
-
- pizzaToppingsScroll = new CyderScrollList(pizzaToppingsScrollLength, pizzaToppingsScrollLength,
- CyderScrollList.SelectionPolicy.MULTIPLE);
- pizzaToppings.forEach(topping -> pizzaToppingsScroll.addElement(topping));
-
- JLabel pizzaToppingsLabel = pizzaToppingsScroll.generateScrollList();
- pizzaToppingsLabel.setBounds(320, 250, 200, 200);
- pizzaFrame.getContentPane().add(pizzaToppingsLabel);
-
- JLabel Extra = new JLabel(EXTRAS);
- Extra.setForeground(CyderColors.navy);
- Extra.setFont(CyderFonts.SEGOE_20);
- Extra.setBounds(40, 510, 130, 30);
- pizzaFrame.getContentPane().add(Extra);
-
- JLabel breadSticksLabel = new JLabel(BREAD_STICKS);
- breadSticksLabel.setFont(CyderFonts.SEGOE_20);
- breadSticksLabel.setForeground(CyderColors.navy);
- breadSticksLabel.setBounds(130, 470, 150, 30);
- pizzaFrame.getContentPane().add(breadSticksLabel);
-
- breadSticks = new CyderCheckbox();
- breadSticks.setHorizontalAlignment(SwingConstants.CENTER);
- breadSticks.setNotChecked();
- breadSticks.setBounds(165, 505, 50, 50);
- pizzaFrame.getContentPane().add(breadSticks);
-
- JLabel saladLabel = new JLabel(SALAD);
- saladLabel.setFont(CyderFonts.SEGOE_20);
- saladLabel.setForeground(CyderColors.navy);
- saladLabel.setBounds(310, 470, 150, 30);
- pizzaFrame.getContentPane().add(saladLabel);
-
- salad = new CyderCheckbox();
- salad.setHorizontalAlignment(SwingConstants.CENTER);
- salad.setNotChecked();
- salad.setBounds(315, 505, 50, 50);
- pizzaFrame.getContentPane().add(salad);
-
- JLabel sodaLabel = new JLabel(SODA);
- sodaLabel.setFont(CyderFonts.SEGOE_20);
- sodaLabel.setForeground(CyderColors.navy);
- sodaLabel.setBounds(445, 470, 150, 30);
- pizzaFrame.getContentPane().add(sodaLabel);
-
- soda = new CyderCheckbox();
- soda.setHorizontalAlignment(SwingConstants.CENTER);
- soda.setNotChecked();
- soda.setBounds(445, 505, 50, 50);
- pizzaFrame.getContentPane().add(soda);
-
- JLabel orderCommentsLabel = new JLabel(ORDER_COMMENTS);
- orderCommentsLabel.setFont(CyderFonts.SEGOE_20);
- orderCommentsLabel.setForeground(CyderColors.navy);
- orderCommentsLabel.setBounds(210, 565, 200, 30);
- pizzaFrame.getContentPane().add(orderCommentsLabel);
-
- orderComments = new JTextArea(5, 20);
- orderComments.setFont(CyderFonts.SEGOE_20);
- orderComments.setAutoscrolls(true);
- orderComments.setLineWrap(true);
- orderComments.setWrapStyleWord(true);
- orderComments.setSelectionColor(CyderColors.selectionColor);
- orderComments.setBorder(new LineBorder(new Color(0, 0, 0)));
-
- CyderScrollPane orderCommentsScroll = new CyderScrollPane(orderComments,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
- ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
- orderCommentsScroll.setThumbColor(CyderColors.regularRed);
- orderCommentsScroll.setBorder(new LineBorder(CyderColors.navy, 5, false));
- orderCommentsScroll.setBounds(80, 600, 600 - 2 * 80, 120);
- pizzaFrame.getContentPane().add(orderCommentsScroll);
-
- CyderButton placeOrder = new CyderButton(PLACE_ORDER);
- placeOrder.setFont(CyderFonts.SEGOE_20);
- placeOrder.addActionListener(e -> placeOrderAction());
- placeOrder.setBounds(80, 740, 200, 40);
- pizzaFrame.getContentPane().add(placeOrder);
-
- CyderButton resetPizza = new CyderButton(RESET);
- resetPizza.setFont(CyderFonts.SEGOE_20);
- resetPizza.addActionListener(e -> reset());
- resetPizza.setBounds(180 + 100 + 40, 740, 200, 40);
- pizzaFrame.getContentPane().add(resetPizza);
-
- pizzaFrame.finalizeAndShow();
- }
-
- /**
- * The action to run when the place order button is clicked.
- */
- @ForReadability
- private static void placeOrderAction() {
- String name = nameField.getTrimmedText();
- if (name.isEmpty()) {
- pizzaFrame.notify("Please enter a valid name");
- return;
- }
- name = StringUtil.capsFirstWords(name);
-
- Optional optionalSize = getSize();
- if (optionalSize.isEmpty()) {
- pizzaFrame.notify("Please specify a size");
- return;
- }
- String size = optionalSize.get() + HtmlTags.breakTag;
-
- String crust;
- ImmutableList selectedElements = crustTypeScroll.getSelectedElements();
- if (selectedElements.isEmpty()) {
- crust = THIN;
- } else {
- crust = selectedElements.get(0);
- }
-
- StringBuilder toppingsChosen = new StringBuilder();
- ImmutableList selectedToppings = pizzaToppingsScroll.getSelectedElements();
- if (selectedToppings.isEmpty()) {
- toppingsChosen.append(PLAIN);
- } else {
- selectedToppings.forEach(topping -> toppingsChosen.append(topping).append(HtmlTags.breakTag));
- }
-
- ImmutableList extrasList = getExtras();
- String extras;
- if (extrasList.isEmpty()) {
- extras = NO_EXTRAS;
- } else {
- StringBuilder extraBuilder = new StringBuilder();
- extrasList.forEach(extra -> extraBuilder.append(extra).append(HtmlTags.breakTag));
- extras = extraBuilder.toString();
- }
-
- String comments = StringUtil.getTrimmedText(orderComments.getText());
- if (comments.isEmpty()) {
- comments = NO_COMMENTS;
- }
-
- pizzaFrame.inform("Name: " + HtmlTags.breakTag + name + HtmlTags.breakTag + HtmlTags.breakTag
- + "Size: " + HtmlTags.breakTag + size + HtmlTags.breakTag + HtmlTags.breakTag
- + "Crust: " + HtmlTags.breakTag + crust + HtmlTags.breakTag + HtmlTags.breakTag
- + "Toppings: " + HtmlTags.breakTag + toppingsChosen + HtmlTags.breakTag
- + "Extras: " + HtmlTags.breakTag + extras + HtmlTags.breakTag
- + "Comments: " + HtmlTags.breakTag + comments + HtmlTags.breakTag, informTitle);
- }
-
- /**
- * Returns a list of extras.
- *
- * @return a list of extras
- */
- private static ImmutableList getExtras() {
- ArrayList ret = new ArrayList<>();
-
- if (breadSticks.isChecked()) {
- ret.add(BREAD_STICKS);
- }
- if (salad.isChecked()) {
- ret.add(SALAD);
- }
- if (soda.isChecked()) {
- ret.add(SODA);
- }
-
- return ImmutableList.copyOf(ret);
- }
-
- /**
- * Returns the pizza size if present. Empty optional else.
- *
- * @return the pizza size if present. Empty optional else
- */
- @ForReadability
- private static Optional getSize() {
- if (smallCheckbox.isChecked()) {
- return Optional.of(SMALL);
- } else if (mediumCheckbox.isChecked()) {
- return Optional.of(MEDIUM);
- } else if (largeCheckbox.isChecked()) {
- return Optional.of(LARGE);
- } else {
- return Optional.empty();
- }
- }
-
- /**
- * Resets the state of the pizza widget.
- */
- @ForReadability
- private static void reset() {
- nameField.setText("");
-
- sizeGroup.clearSelection();
-
- crustTypeScroll.deselectAllElements();
- crustTypeScroll.getScrollPane().getHorizontalScrollBar().setValue(0);
- pizzaToppingsScroll.deselectAllElements();
- pizzaToppingsScroll.getScrollPane().getHorizontalScrollBar().setValue(0);
-
- breadSticks.setNotChecked();
- salad.setNotChecked();
- soda.setNotChecked();
-
- orderComments.setText("");
- }
-}
diff --git a/src/main/java/cyder/widgets/package-info.java b/src/main/java/cyder/widgets/package-info.java
deleted file mode 100644
index c281b7261..000000000
--- a/src/main/java/cyder/widgets/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Cyder widgets for performing conversions, operations, and visualizations.
- */
-package cyder.widgets;