15
\$\begingroup\$

You know those Windows boxes where you can only do one thing?

Windows Error Box: Proceeding will delete the contents of your hard drive. What do you want to do? <Proceed> <Delete>

Let's take this to the next level!

Challenge

Make a dialog box with a button that follows your cursor everywhere!

Specs

No input may be taken. There may be output to either STDOUT or STDERR. You must open a window with one button (no text is necessary, but text may be contained in either the window title, the dialog box, or the button). The button must be clickable, and it must always follow under your cursor so that you can only click it. Upon clicking, it can do anything you want, but please do not make it crash a computer because I will be testing this... The dialog box must stay open for as long as the button is not pressed, but it does not need to close when the button is closed.

Assumptions that you can make

  • You may assume that the cursor will stay within the drawing canvas.
  • You may assume that the window will stay in focus, but you must not put the window out of focus as long as the button is not pressed.

Example Pseudocode

Here's some example pseudocode:

Open Dialog Box
Add Button to Dialog Box at position X, Y
WHILE True:
    SET Dialog Box to CursorX - X, CursorY - Y

Test Cases cannot be provided for this challenge

This is a code-golf challenge, so the shortest valid submission by March 14th (Pi Day) wins!

\$\endgroup\$

10 Answers 10

9
\$\begingroup\$

MATLAB, 86 63 bytes

set(warndlg,'WindowButtonM',@(s,e)movegui(get(0,'Po')-[99,20]))

This solution takes advantage of MATLAB's (typically annoying) ability to use partial property names as long as the part that is provided is unique to only the property of interest.

This solution uses the builtin warndlg to create a warning dialog with an "OK" button. This function returns a figure handle which we can then use to set the WindowButtonMotionFcn callback (using the short name 'WindowButtonM').

The callback that is evaluated any time the cursor is moved within the window gets the current position of the cursor (using the PointerLocation property of the root graphics object, using it's short name 'Po'). We then update the Position of the figure using movegui and specifying the new location of the figure after applying an offset of [99, 20] so that the cursor is placed on the button.

When the button is finally clicked, the figure is deleted and all callbacks are automatically released.

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Could you please provide a link to test this code? I don't have the Matlab software, and this code doesn't work with Octave (since it's only compatible with certain Matlab code). Thanks! \$\endgroup\$ – HyperNeutrino Feb 23 '17 at 20:14
  • 3
    \$\begingroup\$ @AlexL. Unfortunately there is no free online utility for showing how this code works. Even if there were, the UI controls aren't going to be rendered in the web interface. I have included the GIF to demonstrate the code working. \$\endgroup\$ – Suever Feb 23 '17 at 20:46
  • \$\begingroup\$ Alright. I won't bother testing then. Good job, have a +1. \$\endgroup\$ – HyperNeutrino Feb 23 '17 at 21:28
  • \$\begingroup\$ A couple of issues on Windows R2014a. You can stop the dialog box from following by: 1. Moving your mouse (along with the dialog) box to the taskbar (my taskbar is on the right side of the screen) and the dialog box will stop following the mouse; 2. Moving your mouse fast enough such that the mouse is outside the dialog box at any frame, at which point the box will stop following the mouse. The style of the dialog box is also apparently dependent on something else... with the current code, my mouse barely misses the OK button, and I have to change 99 to 120 to work. Anyway, good work! \$\endgroup\$ – Frenzy Li Feb 27 '17 at 8:11
  • \$\begingroup\$ This is what I see from my perspective. My mouse is somewhere near that red crosshair. \$\endgroup\$ – Frenzy Li Feb 27 '17 at 8:13
4
\$\begingroup\$

C# (Windows Form Application), 200 114 bytes

void F(){var p=Cursor.Position;MouseMove+=(r,t)=>{Controls.Add(new Button());Location=new Point(p.X-30,p.Y-40);};}

Un-Golfed

void F()
{
     Controls.Add(new Button());

     MouseMove += (r, t) =>
     {
        var p = Cursor.Position;
        Location = new Point(p.X - 30, p.Y - 40);
     };
}

Old 200-byte solution:

public void F(){var t=this;var b=new Button();b.Click+=delegate{t.Close();};t.Controls.Add(b);t.Show();for(;;){Application.DoEvents();t.Location=new Point(Cursor.Position.X-30,Cursor.Position.Y-40);}}

Un-Golfed

    public void F()
    {
        var t = this;
        var b = new Button();

        b.Click += delegate
        {
            t.Close();
        };

        t.Controls.Add(b);
        t.Show();

        for (;;)
        {
            Application.DoEvents();
            t.Location = new Point(Cursor.Position.X - 30, Cursor.Position.Y - 40);
        }
    }

enter image description here

\$\endgroup\$
  • 1
    \$\begingroup\$ Good job! +1 :) \$\endgroup\$ – HyperNeutrino Feb 23 '17 at 23:12
  • 1
    \$\begingroup\$ Wait.... so in C#, you can add an event listener by doing Event += listener? That's awesome :-) \$\endgroup\$ – ETHproductions Feb 24 '17 at 22:56
  • \$\begingroup\$ @ETHproductions Could probably do that in C++ too if you overloaded the + operator. Still very succinct. \$\endgroup\$ – Carcigenicate Feb 26 '17 at 1:01
1
\$\begingroup\$

AutoHotkey, 122 115 bytes

MsgBox
WinWait,%A_ScriptName%
Loop{
MouseGetPos,x,y
WinGetPos,a,b
ControlGetPos,c,d,,,Button1
WinMove,x+a-c,y+b-d
}

Demo

\$\endgroup\$
  • 2
    \$\begingroup\$ Nice and simple. Good job! +1 \$\endgroup\$ – HyperNeutrino Feb 24 '17 at 19:56
1
\$\begingroup\$

Java 7, 294 289 286 264 220 bytes

import java.awt.*;public class B extends java.applet.Applet{Button b;public B(){add(b=new Button());}public void paint(Graphics g){Point p=MouseInfo.getPointerInfo().getLocation();b.setLocation(p.x-9,p.y-65);repaint();}}

-22 bytes thanks to MouseInfo (stolen from Zavada) I don't like the awt libraries >.>

I shaved off 44 bytes by removing the main method here. The main method isn't needed if this is launched as an applet. This can be achieved via eclipse's "Run As Java Applet" or by disabling the security manager and using appletviewer, which comes with the JDK (unless you're still able to view applets in web browsers. I don't think chrome allows this).

popup

\$\endgroup\$
  • \$\begingroup\$ Nice job, +1! I agree, the awt libraries are a bit ugly, but it's golfier. \$\endgroup\$ – HyperNeutrino Feb 24 '17 at 21:32
  • \$\begingroup\$ You can save 24 bytes by removing import java.awt.event.*; \$\endgroup\$ – Zavada Feb 24 '17 at 22:48
  • \$\begingroup\$ @Zavada The * wildcard does not recursively import subpackages. I need java.awt.event for the MouseAdapter and MouseEvent \$\endgroup\$ – Poke Feb 24 '17 at 23:32
  • \$\begingroup\$ Apologies, I had a total brainfart! \$\endgroup\$ – Zavada Feb 25 '17 at 0:25
1
\$\begingroup\$

Java, 172 199 235 Bytes

Golfed:

import java.awt.*;interface D{static void main(String[]z){new javax.swing.JDialog(){{setSize(9,99);setVisible(1>0);add(new Button());a();}void a(){for(Point p;;p=MouseInfo.getPointerInfo().getLocation(),setLocation(p.x-9,p.y-70));}};}}

Ungolfed:

import java.awt.*;
interface D{
    static void main(String[]z){
        new javax.swing.JDialog(){
            {
                setSize(9,99);
                setVisible(1>0);
                add(new Button());
                a();
            }
            void a(){

                for(;;) {
                    Point p = MouseInfo.getPointerInfo().getLocation();
                    setLocation(p.x-9,p.y-70);
                }
            }
        };

    }
}

Explanation: I use double brace initialization on my declaration of a new JDialog. This saved bytes by excluding the extension of JDialog (allowing me to save bytes excluding public from main). Inside JDialog's anonymous subclass I make it visible (using 1>0 instead of true) and call a(), which is necessary because the initalizer has a compile-time error if the loop were sat in it normally. I opted to use MouseInfo rather than all the excess code associated with adding a mouse listener.

Edit: Had to increase count by 27 to add add(new java.awt.Button());. I thought JDialogs had an implied button by technicality, but I seem to be wrong.

Edit 2: Had to add setSize and offset mouse location to make the button clickable.

Dialog

\$\endgroup\$
  • \$\begingroup\$ This doesn't quite work; I can't press the button because the cursor is constantly on the top-left corner of the window. Please fix this! :) \$\endgroup\$ – HyperNeutrino Feb 25 '17 at 1:24
  • \$\begingroup\$ Apologies, should be fixed now! \$\endgroup\$ – Zavada Feb 25 '17 at 1:58
  • \$\begingroup\$ Yep. Works now! +1 \$\endgroup\$ – HyperNeutrino Feb 26 '17 at 0:59
  • \$\begingroup\$ I didn't know/remember MouseInfo was a thing. This is a neat answer. \$\endgroup\$ – Poke Feb 26 '17 at 1:03
  • 1
    \$\begingroup\$ @Poke Thanks. I saw your answer using applets, and I have an unreasonable hatred for applets, so I felt it would be cute to do in swing. Your answer is nice though :) \$\endgroup\$ – Zavada Feb 27 '17 at 16:24
0
\$\begingroup\$

Modified Processing Js 102 108 bytes

draw=function(){background(0);rect(mouseX,mouseY,9,9);rect(mouseX,mouseY,4,4);if(mouseIsPressed){fill(9);}};

Try it online! Just updated my link!

It just draws a rectangle that follows your mouse and a smaller rectangle inside of it that you click and it turns red. It works but is not amazing. This version if very strict on braces and all of that :(

\$\endgroup\$
  • \$\begingroup\$ You can remove the braces around fill \$\endgroup\$ – Cows quack Feb 23 '17 at 16:40
  • \$\begingroup\$ @KritixiLithos I actually can't :( \$\endgroup\$ – Christopher Feb 23 '17 at 16:41
  • \$\begingroup\$ It is a strictly type language version \$\endgroup\$ – Christopher Feb 23 '17 at 16:44
  • \$\begingroup\$ You could use another type of Processing to save bytes then \$\endgroup\$ – Cows quack Feb 23 '17 at 16:47
  • \$\begingroup\$ @KritixiLithos actually then I would also have to set up a screen size and that would add bytes. (Side note I just got kicked from chat for "inappropriate content any idea why? It was a bot too. chat.stackexchange.com/messages/35631789/history was why \$\endgroup\$ – Christopher Feb 23 '17 at 16:49
0
\$\begingroup\$

Clojure, 525 bytes

(ns d(:require[quil.core :as q][quil.middleware :as m]))(def w 500)(def h 200)(def t 30)(def n 200)(def m 100)(q/defsketch d :size[999 999]:setup(fn[](q/stroke 0 0 0)(q/text-font(q/create-font""(* t 1.3))){:x 0 :y 0}):draw(fn[{x :x y :y}](let[r q/rect f q/fill o(- x(/ w 2))p(- y (/ h 2))](q/background 99 99 99)(f 0 0 255)(r o p w h)(f 200 200 200)(r o(+ p t)w(- h t))(f 255 0 0)(r(-(+ o w)t)p t t)(f 255 255 255)(q/text"X"(- (+ o w) t)(+ p t))(r(- x(/ n 2))(- y (/ m 2))n m))):mouse-moved(fn[_ e]e):middleware[m/fun-mode])

Does not create a genuine Windows dialog. Instead, it builds a fake one, and creates a dummy (non-functioning) button in the middle.

This was allowed by the OP in the comments.

Uses the Quil library.

(ns bits.golf.following-dialog
  (:require [quil.core :as q]
            [quil.middleware :as m]))

(def width 500)
(def height 200)

(def top-bar-height 30)

(def b-width 200)
(def b-height 100)

(defn -main []
  (q/defsketch d
    :size [999 999]
    :setup (fn []
             ; Set the border color
             (q/stroke 0 0 0)

             ; Set the font size
             (q/text-font (q/create-font "" (* top-bar-height 1.3)))

             ; The initial state
             {:x 0 :y 0})

    :draw (fn [{x :x y :y}]
            (let [r q/rect ; Shortcut functions for brevity
                  f q/fill

                  ; The top-left coordinates of the window
                  window-x  (- x (/ width 2))
                  window-y (- y (/ height 2))]

              ; Wipe the previous screen
              (q/background 99 99 99)

              ; Blue top bar
              (f 0 0 255)
              (r window-x
                 window-y
                 width height)

              ; Grey window background
              (f 200 200 200)
              (r window-x
                 (+ window-y top-bar-height)
                 width (- height top-bar-height))

              ; Red top right "button"
              (f 255 0 0)
              (r (- (+ window-x width)
                    top-bar-height)
                 window-y
                 top-bar-height top-bar-height)

              ; The X
              (f 255 255 255)
              (q/text "X" (- (+ window-x width) top-bar-height)
                          (+ window-y top-bar-height))

              ; The main "button"
              (r (- x (/ b-width 2))
                 (- y (/ b-height 2))
                 b-width
                 b-height)))

    ; When the mouse is moved, set the current state to the event object, which
    ;  conveniently has :x and :y properties
    :mouse-moved (fn [_ e] e)

    ; Needed for ease of state management. May try to factor out.
    :middleware [m/fun-mode]))

Fake Dialog

\$\endgroup\$
  • \$\begingroup\$ I'm tempted to not upvote this because your rep is 1000 and it looks so nice... I'm going to count this as a valid solution (simply because I've already validated a similar solution that doesn't create a "real" window), so have a +1. :P \$\endgroup\$ – HyperNeutrino Feb 26 '17 at 0:58
  • \$\begingroup\$ @HyperNeutrino Thanks, even though this is gross overkill for the task, and an even 1k rep is nice. I had fun with it! Maybe I'll create an AWT version too just for comparison. Will probably be like half the length. \$\endgroup\$ – Carcigenicate Feb 26 '17 at 1:00
  • \$\begingroup\$ You can just wait for 2k to then! :D \$\endgroup\$ – HyperNeutrino Feb 27 '17 at 3:58
0
\$\begingroup\$

Pug/Slim + CSS/SCSS/LESS/Stylus + ES6 Javascript (98 Bytes)

Try it online!

Pug (10 UTF-8 Bytes)

button#a X

Stylus (18 UTF-8 Bytes)

#a{position:fixed}

JS (70 UTF-8 Bytes)

onmousemove=e=>{with(a.style){top=e.clientY+'px';left=e.clientX+'px'}}

Decompiled, Ungolfed and explained Snippet:

document.addEventListener('mousemove', function(e) {
  // Get element with an id of "id"
  var el = document.getElementById("id");
  // Set the vertical position
  el.style.top = e.clientY + 'px';
  // Set the horizontal position
  el.style.left = e.clientX + 'px';
})
/* Get element with an id of "id" */

#id {
  /* Position it relative to the viewport*/
  position: fixed;
}
<!-- A basic HTML button with an ID of "id" -->
<button id='id'>
  X
</button>

\$\endgroup\$
0
\$\begingroup\$

Mathematica 226 Bytes

The mouse position relative to the screen is tracked by the front end and the window position of the dialog notebook is moved whenever the mouse moves. Pretty simple, but the commands are very lengthy in terms of letters, as often the case with Mathematica. Clicking OK will close the dialog.

{s,d,w}={SetOptions,Dynamic,WindowMargins->m};With[{p=d@MousePosition["ScreenAbsolute"]},
m=d@{{p[[1]]-50,0},{0,p[[2]]-35}}];s[$FrontEndSession,FrontEndEventActions->{"MouseMoved":>s[a,w]}];a=CreateDialog[{DefaultButton[]},w];

P.S. When you're done testing, run this to remove the front end option.

SetOptions[$FrontEndSession,FrontEndEventActions->None]

screen animation

\$\endgroup\$
  • \$\begingroup\$ Can you add a gif to prove functionality? I can't test Mathematica. Thanks! \$\endgroup\$ – HyperNeutrino Feb 23 '17 at 23:13
-1
\$\begingroup\$

Javascript (ES6) + HTML + CSS, 139 bytes

HTML:

<d id=d><button>X

CSS:

d{background:red;padding:9px;position:absolute

Javascript:

onmousemove=e=>{with(d.style){top=e.clientY-20+'px';left=e.clientX-20+'px'}}

Since you can't position alert dialogs, I made my custom super fancy dialog in HTML. The javascript registers an event handler on the window object and sets the position to the coordinates of the event.

Try it online: https://jsfiddle.net/1yohswje/

\$\endgroup\$
  • \$\begingroup\$ I'm going to say this is invalid, because it doesn't create anything similar to a legitimate "window", and as well, you can't tell that it's meant to be a window with a button. However, it is an interesting solution! \$\endgroup\$ – HyperNeutrino Feb 26 '17 at 1:01
  • \$\begingroup\$ @HyperNeutrino I've updated my answer. What do you think of this? \$\endgroup\$ – corvus_192 Feb 26 '17 at 12:42
  • \$\begingroup\$ Ok. That complies to my standards now. Have a +1 \$\endgroup\$ – HyperNeutrino Feb 26 '17 at 20:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.