^

Introduction

cmuggui is a library for building GUIs in CMU Graphics.

Install

To install, run pip install cmuggui in the command line. If you prefer, you can clone the repository here.


Classes

Menu

Menu(*args, fill=Colors.gray, border=Colors.darkerGray, borderWidth=2, parent = None, debug: bool = False, **kwargs):

The Menu class subclasses the Rect class from CMU Graphics. This means that normal Rect arguments like left and top are still passed.

Keyword Arguments

The keyword arguments seen in the definition (aside from debug) are the default styles for Menu objects.

parent

A Menu object.

debug

When True, lines are drawn that show alignment and where the border is. This is useful if fill and border are invisible, or you need guidelines to help align elements. This also automatically calls the getData() method.

Attributes

Since Menu subclasses Rect, it has all the attributes a regular Rect.

MENUS, BUTTONS, TITLES

These are class level attributes that hold the data attribute of all instances of that class. For insatnce, every buttons data attribute will be contained Menu.BUTTONS. They are all of type List, so they can be accessed with bracket notation.

parent

The Rect of the parent. This will be None if no parent is passed.

buttons

A list of all the buttons that are children of this menu.

buttonsData

A list of all of the buttons data attribute.

debug

Whether or not debug mode is enabled.

dbNS

The line that runs from the center top to the center bottom of the button.

dbEW

The line that runs from the center left to the center bottom of the button.

dbNWSE

The line that runs from the top left corner to the bottom right corner of the button.

dbNESW

The line that runs from the top right corder to the bottom left corner of the button.

dbBorder

The border of the button.

data

A dictionary containing all the data of the button.

Methods

getData()

Returns the data attribute.



{
    "Class": f"{self.__class__.__name__}",
    "Parent": f"{self.parent}",
    "Debug": self.debug,
    "Dimensions": {
        "TopLeft": (self.left, self.top),
        "TopRight": (self.right, self.top),
        "BottomLeft": (self.left, self.bottom),
        "BottomRight": (self.right, self.bottom),
        "Width": self.width,
        "Height": self.height,
        "Center": (self.centerX, self.centerY)
    },
    "BackgroundFill": self.fill,
    "BorderFill": self.border,
    "BorderWidth": self.borderWidth,
    "IsVisible": self.visible,
    "Buttons": self.buttonsData
}

addEventListener(x, y)

Event listeners are created inside of the onMousePress built in function.

menuObject = Menu(
    0, 0,
    133, 400
)

buttonObject = Menu.Button(
    menuObject,
    0, 15,
    50, 20,
    onclick=Functions.QQUIT,
    fill=Colors.CSS3.slategray,
    border=Colors.CSS3.black,
    borderWidth=4
)

def onMousePress(x, y):
    menuObject.addEventListener(x, y)

When the button is clicked, its onclick property is called.

Differences from Menu.Button.addEventListener

When this version of the event listener is called, it loops through all of the child buttons of the menu and checks to see if the clicks coordinates collides with the button.

Menu.Button

Menu.Button(parent, *args, 
textValue = "", textFill = rgb(0,0,0), textSize = 12.0, textFont = "arial", textOpacity = 100,
textIsBold = False, textIsItalic = False, textIsVisible = True,
onclick = None, debug = False, **kwargs)

Buttons are automatically aligned to the center of their parent Menu.

Arguments

parent

A Menu object.

*args

These are treated mostly the same as they would be if this were a regualr Rect, aside from left and top.

  • Left: Places the button in relation to the value of its parent menus centerX value, instead of placing it in relation to the app window. Negative values move the button left, while positive values move the button right.
  • Top: Places the button in relation to the value of its parent menus top value, instead of placing it in relation to the app window.

Keyword Arguments

textValue

The text displayed on the button.

textFill

The color of the text.

textFont

The font of the text.

textSize

The size of the text.

textIsBold

Whether or not the text should be bold.

textIsItalic

Whether or not the text should be italic.

textOpacity

The opacity of the text.

textIsVisible

Whether or not the text should be visible.

onclick

The name of a function. Called when the parent menu has an event listener. Passing the name of the function with parenthesis will call the function (foo() instead of foo).

debug

When True, lines are drawn that show alignment and where the border is. This is useful if fill and border are invisible, or you need guidelines to help align elements. This also automatically calls the getData() method.

Attributes

Since Menu.Button subclasses Rect, it has all of the attributes a normal Rect would normally have.

parent

The parent Menu of the button.

onclick

The function the button is assigned to.

hasEventListener

Whether the button has an event listener or not.

text

A Label object. This is the text that is displayed on the button.

textValue

The value of the text that is displayed on the button.

textFill

The color of the text.

textSize

The size of the text.

textFont

The font of the text.

textIsBold

Whether or not the text is bold.

textIsItalic

Whether or not the text is italic.

textIsVisible

Whether or not the text is visible.

textOpacity

The opacity of the text.

debug

Whether or not debug mode is enabled.

dbNS

The line that runs from the center top to the center bottom of the button.

dbEW

The line that runs from the center left to the center bottom of the button.

dbNWSE

The line that runs from the top left corner to the bottom right corner of the button.

dbNESW

The line that runs from the top right corder to the bottom left corner of the button.

dbBorder

The border of the button.

data

A dictionary containing all the data of the button.

Methods

getData()

Returns the data attribute.



{
    "Class": f"{self.__class__.__name__}",
    "Parent": f"{self.parent}",
    "Debug": self.debug,
    "OnClickFunction": f"{self.onclick}",
    "HasEventListener": self.hasEventListener,
    "BoundingBox": {
        "Dimensions": {
            "TopLeft": (self.left, self.top),
            "TopRight": (self.right, self.top),
            "BottomLeft": (self.left, self.bottom),
            "BottomRight": (self.right, self.bottom),
            "Width": self.width,
            "Height": self.height,
            "Center": (self.centerX, self.centerY)
        },
        "BackgroundFill": self.fill,
        "BorderFill": self.border,
        "BorderWidth": self.borderWidth,
        "Opacity": self.opacity,
        "IsVisible": self.visible
    },
    "Text": {
        "Dimensions": {
            "TopLeft": (self.text.left, self.text.top),
            "TopRight": (self.text.right, self.text.top),
            "BottomLeft": (self.text.left, self.text.bottom),
            "BottomRight": (self.text.right, self.text.bottom),
            "Width": self.text.width,
            "Height": self.text.height,
            "Center": (self.text.centerX, self.text.centerY),
        },
        "Value": self.text.value,
        "Fill": self.text.fill,
        "Font": self.text.font,
        "Size": self.text.size,
        "IsBold": self.text.bold,
        "IsItalic": self.text.italic,
        "Opacity": self.text.opacity,
        "IsVisible": self.text.visible
    }
}

Event Listeners

addEventListener(x, y)

Event listeners are defined inside of the onMousePress function from CMU Graphics. When an event listener is defined, they must take x and y as arguments. An example is shown below.

Example Implementation

def onMousePress(x, y):
  buttonObject.addEventListener(x, y)

Differences between Menu.addEventListener

This version of the event listener only checks to see if a specifc button has been clicked, instead of looping through a list.

Menu.Title

Menu.Title(parent, *args, **kwargs)
Titles, like buttons, are automatically aligned to the center of their parent menu.

Arguments

parent

A Menu object.

*args, **kwargs

Since this class subclasses Label, it has all the regular *args and **kwargs of a regular Label.

Attributes

Since this class subclasses Label, it has all the regular attributes of a Label.

parent

The Rect of the parent. This will be None if no parent is passed.

Methods

getData()

Returns the data attribute.


{
    "Class": f"{self.__class__.__name__}",
    "Parent": f"{self.parent}",
    "Dimensions": {
        "TopLeft": (self.left, self.top),
        "TopRight": (self.right, self.top),
        "BottomLeft": (self.left, self.bottom),
        "BottomRight": (self.right, self.bottom),
        "Width": self.width,
        "Height": self.height,
        "Center": (self.centerX, self.centerY)
    },
    "Color": self.fill,
    "Value": self.value,
    "Fill": self.fill,
    "Font": self.font,
    "Size": self.size,
    "IsBold": self.bold,
    "IsItalic": self.italic,
    "Opacity": self.opacity,
    "IsVisible": self.visible
}
            

VerticalTitle

VerticalTitle(*args, spacing=0, **kwargs)

A title, except written vertically instead of horrizontally. Each character is its own Menu.Title.

Arguments

*args, **kwargs

Since this class subclasses Menu.Title, it takes all the regular *args and **kwargs.

spacing

How far apart each letter should be spaced vertically.

Attributes

spacing

How far apart each letter is spaced vertically.

chars

A CMU Graphics Group object that contains each character in the title.

data

A dict that contains data about the object.

Methods

getData()

Returns the data attribute of the object.


{
  "Class": f"{self.__class__.__name__}",
  "Parent": f"{self.parent}",
  "Position": (self.chars.centerX, self.chars.centerY),
  "Value": self.value,
  "Color": f"{self.fill}",
  "Font": self.font,
  "Size": self.size,
  "IsBold": self.bold,
  "IsItalic": self.italic,
  "Opacity": self.opacity,
  "IsVisible": self.visible
}

Functions

This class defines utiity functions. You do not need to create an object of this class to use its methods.

Functions.NOFUNCTION()

A function that does nothing.

Functions.QUIT()

Quits the program using sys.exit(0).

Functions.QQUIT()

Quits the program by raising a KeyboardInterrupt.

Functions.toggleVisibility(object)

Toggles the visibilty of the object that is passed.

Functions.translate(object, translateX, translateY)

Translates the centerX and centerY of the object that is passed.

Functions.rotate(object, degrees, origin="object_Center", originX=None, originY=None)

Rotates the object that is passed by an amount in degrees.

Possible Origins

Origin Description
"object_Center" (default) The center of the object.
"object_TopLeft" The top left coordinate of the object.
"object_TopRight" The top right coordinate of the object.
"object_BottomLeft" The bottom left coordinate of the object.
"object_BottomRight" The bottom right coordinate of the object.
"origin_Custom" A custom coordinate to rotate the object around. The origin is determined by originX and originY

Functions.hover(object, mode="darken", darkenModAmount=0.9, lightenModAmount=1.1, hoverFill=True, hoverBorder=True, hoverText=True)

object

Either a Menu or Menu.Button object. This objects fill and border properties must be rgb values. Passing an object with a gradient or string color value will raise an error.

mode

Whether to darken or lighten the object on hover. Possible values are "darken" and "lighten".

darkenModAmount

How much darker to make the object on hover.

lighenModAmount

How much lighter to make the object on hover.

hoverFill

Whether or not the background color should be effected.

hoverBorder

Whether or not the border color should be effected.

hoverText

Whether or not the text color should be effected.

Implementing Hover

Example

In its current state, Functions.hover requires a lot of boilerplate code to work properly. This function only modifies the fill and border properties of the button.


from cmu_graphics import *

app.hovering = 0

# rest of your code

exampleMenu = Menu(
  0, 0,
  133, 400,
  fill=rgb(70,70,70),
  border=rgb(20,20,20),
  borderWidth=5
)

exampleButton = Menu.Button(
  exampleMenu,
  -30, 20,
  55, 20,
  fill=Colors.CSS3.slategray,
  border=gradient(Colors.CSS3.darkslategray, Colors.CSS3.lightslategray),
  textValue="Example",
)
exampleButtonData = exampleButton.getData()

def onMouseMove(x, y):
  if exampleButton.contains(x, y):
    app.hovering += 1
    Functions.hover(exampleButton, mode="lighen", lighenModAmount=1.3)
  else:
    exampleButton.fill = exampleButtonData["BoundingBox"]["BackgroundFill"]
    exampleButton.border = exampleButtonData["BoundingBox"]["BorderFill"]
    app.hovering = 0

cmu_graphics.run()

Explanation

Functions.hover uses an app variable called hovering. When the button is hovered over, the hovering varaible is increased, telling the function that something is being hovered. Then, the function makes the fill and border ligher. In the else block, we set the modified properties back to their original state and tell the app that the button is no longer being hovered.


Colors

Colors are accessed like this: Colors.COLOR_NAME. So, to access the gray color, you would do Colors.gray.



Name Value
gray rgb(200, 200, 200)
darkGray rgb(175, 175, 175)
darkerGray rgb(100, 100, 100)

Colors.CSS3

This class defines the colors available in CSS3. They are the same as the colors defined by CMU Graphics, just accessed in a different way. To access them, do Colors.CSS3.COLOR_NAME. So, to access the color "cornflower blue", you would do Colors.CSS3.cornflowerblue. Note that COLOR_NAME is all lower case.

A list of all CSS3 colors can be found here: CSS3 Color Names

Colors.DEBUG

These colors define the colors of the lines shown when the debug kwarg = True. While while it is possible to use and modify these colors, it is not recommended.



Name Value
NORTHWEST_SOUTHEAST rgb(255, 0, 255)
NORTHEAST_SOUTHWEST rgb(255, 255, 0)
NORTH_SOUTH rgb(255, 0, 0)
EAST_WEST rgb(0, 128, 0)
BORDER rgb(0, 0, 255)

Example

from cmu_graphcs import *
from cmuggui import *

app.hovering = 0

def start():
  print("program started")

exampleMenu = Menu(
  0, 0,
  133, 400,
  fill=Colors.CSS3.lightsteelblue,
  border=Colors.CSS3.lightslategray,
  borderWidth=3
)

exampleButton = Menu.Button(
  exampleMenu,
  -20, 10,
  40, 30,
  textValue="Play"
)
exampleButtonData = exampleButton.getData()
           
quitButton = Menu.Button(
  exampleMenu,
  -10, 365,
  30, 10,
  textValue="Quit",
  textSize=10
)
quitButtonData = quitButton.getData()

def onMousePress(x, y):
  exampleButton.addEventListener(x, y, onclick=start)
  quitButton.addEventListener(x, y, onclick=Functions.QUIT)

def onMouseMove(x, y):
  if exampleButton.contains(x, y):
    app.hovering += 1
    Functions.hover(exampleButton)
  elif quitButton.contains(x, y):
    app.hovering += 1
    Functions.hover(quitButton)
  else:
    exampleButton.fill = rgb(*exampleButtonData["BoundingBox"]["BackgroundFill"])
    exampleButton.border = rgb(*exampleButtonData["BoundingBox"]["BorderFill"])

    quitButton.fill = rgb(*quitButtonData["BoundingBox"]["BackgroundFill"])
    quitButton.border = rgb(*quitButtonData["BoundingBox"]["BorderFill"])
    
    app.hovering = 0

cmu_graphics.run()


This page is liscensed under Creative Commons Zero v1.0 Universal | GitHub repository