diff --git a/java/2-3-widgets/WidgetDemo.java b/java/2-3-widgets/WidgetDemo.java new file mode 100644 index 0000000000000000000000000000000000000000..32a516cffa321dd011adb25bf65ce38c0dd9996f --- /dev/null +++ b/java/2-3-widgets/WidgetDemo.java @@ -0,0 +1,115 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +public class WidgetDemo { + + public static void main(String[] args) { + WidgetDemo demo = new WidgetDemo(); + } + + JLabel label; + + WidgetDemo() + { + JFrame f = new JFrame("WidgetDemo.java"); + f.setSize(500, 200); + f.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + + // create a button and add a listener for events + JButton button = new JButton("My Button"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + label.setText("button"); + } + }); + + // create a slider + JSlider slider = new JSlider(0, 100, 50); + slider.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + JSlider s = (JSlider)e.getSource(); + label.setText("slider " + s.getValue()); + } + }); + + // create a radio button group + ButtonGroup radiobuttons = new ButtonGroup(); + JPanel radioPanel = new JPanel(new GridLayout(1, 0)); + for (String s: new String[] {"A", "B", "C"}) + { + JRadioButton rb = new JRadioButton(s); + rb.addActionListener(radioButtonListener); + radiobuttons.add(rb); + radioPanel.add(rb); + } + + // create a menu + JMenu menu = new JMenu("Choices"); + // create some menu choices + for (String s: new String[] {"apple", "orange", "banana", "pear" }) + { + // add this menu item to the menu + JMenuItem mi = new JMenuItem(s); + // set the listener when events occur + mi.addActionListener(menuItemListener); + // add this menu item to the menu + menu.add(mi); + } + JMenuBar menubar = new JMenuBar(); + menubar.add(menu); + + // create a label + // (we'll use this to display messages) + label = new JLabel("message"); + // set some properties to customize how it looks + label.setPreferredSize(new Dimension(500, 60)); + label.setHorizontalAlignment( SwingConstants.CENTER ); + label.setBackground(Color.WHITE); + label.setBorder(BorderFactory.createLineBorder(Color.black)); + label.setFont(new Font("SansSerif", Font.PLAIN, 30)); + + + // define the layout + // http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html + + + // add the widgets + f.add(button); + f.add(slider); + f.add(menubar); + f.add(radioPanel); + f.add(label); + + f.setLayout(new FlowLayout()); + + f.setVisible(true); + } + + // create a menu item listener + MenuItemListener menuItemListener = new MenuItemListener(); + + class MenuItemListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + JMenuItem mi = (JMenuItem)e.getSource(); + label.setText(mi.getText()); + } + } + + // create a radio button listener + RadioButtonListener radioButtonListener = new RadioButtonListener(); + + class RadioButtonListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + JRadioButton rb = (JRadioButton)e.getSource(); + label.setText(rb.getText()); + } + } + +} diff --git a/java/2-3-widgets/makefile b/java/2-3-widgets/makefile new file mode 100644 index 0000000000000000000000000000000000000000..dcea5ae9efc87a545872d413dc3fba0f2c6dd814 --- /dev/null +++ b/java/2-3-widgets/makefile @@ -0,0 +1,15 @@ +# super simple makefile +# call it using 'make NAME=name_of_code_file_without_extension' +# (assumes a .java extension) +NAME = "WidgetDemo" + +all: + @echo "Compiling..." + javac $(NAME).java + +run: all + @echo "Running..." + java $(NAME) + +clean: + rm -rf *.class diff --git a/x/2-3-widgets/button.cpp b/x/2-3-widgets/button.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5962e72fb015ba9bcbf3dd717da94a6185c11dbd --- /dev/null +++ b/x/2-3-widgets/button.cpp @@ -0,0 +1,257 @@ +/* +CS 349 Code Examples: X Windows and XLib + + button.cpp Implement a ToggleButton UI Widget + +- - - - - - - - - - - - - - - - - - - - - - + +See associated makefile for compiling instructions + +*/ + +#include <cstdlib> + +#include <unistd.h> +#include <sys/time.h> +#include <math.h> + +#include <iostream> +#include <sstream> +#include <list> +#include <vector> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + + + +// get microseconds +unsigned long now() { + timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} + + +using namespace std; + + +// - - - X globals - - - + +struct XInfo { + Display* display; + Window window; + int screen; + GC gc; +}; + +XInfo xinfo; + +// frames per second to run animation loop +int FPS = 60; + +// helper function to set X foreground colour +enum Colour {BLACK, WHITE}; +void setForeground(Colour c) { + if (c == BLACK) { + XSetForeground(xinfo.display, xinfo.gc, BlackPixel(xinfo.display, xinfo.screen)); + } else { + XSetForeground(xinfo.display, xinfo.gc, WhitePixel(xinfo.display, xinfo.screen)); + } +} + + +// isPaused functionality +bool isPaused = false; +// isPaused callback (a simple event handler) +void togglePause(bool isOn) { + isPaused = isOn; +} + +// A toggle button widget +class ToggleButton { + +public: + + ToggleButton(int _x, int _y, void (*_toggleEvent)(bool)) { + x = _x; + y = _y; + toggleEvent = _toggleEvent; + isOn = false; + diameter = 50; + } + + // the CONTROLLER + void mouseClick(int mx, int my) { + float dist = sqrt(pow(mx - x, 2) + pow(my - y, 2)); + if (dist < diameter / 2) { + toggle(); + } + } + + // the VIEW + void draw() { + + if (isOn) { + setForeground(BLACK); + XFillArc(xinfo.display, xinfo.window, xinfo.gc, + x - diameter / 2, + y - diameter / 2, + diameter, diameter, + 0, 360 * 64); + setForeground(WHITE); + XDrawArc(xinfo.display, xinfo.window, xinfo.gc, + x - diameter / 2, + y - diameter / 2, + diameter, diameter, + 0, 360 * 64); + } else { + setForeground(WHITE); + XFillArc(xinfo.display, xinfo.window, xinfo.gc, + x - diameter / 2, + y - diameter / 2, + diameter, diameter, + 0, 360 * 64); + setForeground(BLACK); + XDrawArc(xinfo.display, xinfo.window, xinfo.gc, + x - diameter / 2, + y - diameter / 2, + diameter, diameter, + 0, 360 * 64); + } + } + +private: + + // VIEW "essential geometry" + int x; + int y; + int diameter; + + // toggle event callback + void (*toggleEvent)(bool); + + // the MODEL + bool isOn; + + void toggle() { + isOn = !isOn; + toggleEvent(isOn); + } +}; + + +int main( int argc, char *argv[] ) { + + xinfo.display = XOpenDisplay(""); + if (xinfo.display == NULL) exit (-1); + int screennum = DefaultScreen(xinfo.display); + long background = WhitePixel(xinfo.display, screennum); + long foreground = BlackPixel(xinfo.display, screennum); + xinfo.window = XCreateSimpleWindow(xinfo.display, DefaultRootWindow(xinfo.display), + 10, 10, 300, 200, 2, foreground, background); + XSelectInput(xinfo.display, xinfo.window, + ButtonPressMask | KeyPressMask); // select events + XMapRaised(xinfo.display, xinfo.window); + XFlush(xinfo.display); + + XEvent event; // save the event here + + // ball postition, size, and velocity + XPoint ballPos; + ballPos.x = 50; + ballPos.y = 50; + int ballSize = 50; + XPoint ballDir; + ballDir.x = 3; + ballDir.y = 3; + + // create gc for drawing + xinfo.gc = XCreateGC(xinfo.display, xinfo.window, 0, 0); + + // time of last xinfo.window paint + unsigned long lastRepaint = 0; + + XWindowAttributes w; + XGetWindowAttributes(xinfo.display, xinfo.window, &w); + + ToggleButton toggleButton(150, 100, &togglePause); + + // event loop + while ( true ) { + + // TRY THIS + // comment out this conditional to see what happens when + // events block (run the program and keep pressing the mouse) + if (XPending(xinfo.display) > 0) { + XNextEvent( xinfo.display, &event ); + + switch ( event.type ) { + + // mouse button press + case ButtonPress: + // cout << "ButtonPress" << endl; + toggleButton.mouseClick(event.xbutton.x, event.xbutton.y); + break; + + case KeyPress: // any keypress + KeySym key; + char text[10]; + int i = XLookupString( (XKeyEvent*)&event, text, 10, &key, 0 ); + if ( i == 1 && text[0] == 'q' ) { + XCloseDisplay(xinfo.display); + exit(0); + } + break; + } + } + + unsigned long end = now(); + + if (end - lastRepaint > 1000000 / FPS) { + + + // clear background + XClearWindow(xinfo.display, xinfo.window); + + // draw ball from centre + setForeground(BLACK); + XFillArc(xinfo.display, xinfo.window, xinfo.gc, + ballPos.x - ballSize / 2, + ballPos.y - ballSize / 2, + ballSize, ballSize, + 0, 360 * 64); + + + if (!isPaused) { + + // update ball position + ballPos.x += ballDir.x; + ballPos.y += ballDir.y; + + // bounce ball + if (ballPos.x + ballSize / 2 > w.width || + ballPos.x - ballSize / 2 < 0) + ballDir.x = -ballDir.x; + if (ballPos.y + ballSize / 2 > w.height || + ballPos.y - ballSize / 2 < 0) + ballDir.y = -ballDir.y; + + } + + toggleButton.draw(); + + XFlush( xinfo.display ); + + lastRepaint = now(); // remember when the paint happened + } + + // IMPORTANT: sleep for a bit to let other processes work + if (XPending(xinfo.display) == 0) { + usleep(1000000 / FPS - (end - lastRepaint)); + } + + + } + XCloseDisplay(xinfo.display); +} diff --git a/x/2-3-widgets/makefile b/x/2-3-widgets/makefile new file mode 100644 index 0000000000000000000000000000000000000000..f100361d1b1ace3ad7e1bcd2e896fb19bc4eac7d --- /dev/null +++ b/x/2-3-widgets/makefile @@ -0,0 +1,19 @@ +# super simple makefile +# call it using 'make NAME=name_of_code_file_without_extension' +# (assumes a .cpp extension) +NAME = "button" + +# Add $(MAC_OPT) to the compile line for macOS +# (should be ignored by Linux, set to nothing if causing problems) +MAC_OPT = -I/opt/X11/include + +all: + @echo "Compiling..." + g++ -o $(NAME) $(NAME).cpp -L/opt/X11/lib -lX11 -lstdc++ $(MAC_OPT) + +run: all + @echo "Running..." + ./$(NAME) + +clean: + -rm *o