{ "info": { "author": "Diego Dorn", "author_email": "diego.dorn@free.fr", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6" ], "description": "# Graphalama\n\n## Aim\n\nPygame is a great and simple way to create basic windowed applications.\nIt is therfore a privilieged entry point for python learners to get out of the console.\nHowever, people often ask for GUI features in pygame: _\"How can I have a simple button ?\"_ or _\"How can the user enter their name ?\"_.\n\nThe goal of this librairy is to answer all those questions and provide the easiest possible interface to create, update, control and manipulate what we will call widgets. (Buttons, TextBoxes, Sliders, Switches...)\n\n### Our principles\n\n- KISS: Keep it sweet and simple\n- Simple and ugly are not synonyms\n- Simple can be powerfull\n- Simple should be customisable\n- No code is better than ugly code\n\n## Installation\n\nYou can install a stable version using pip\n```\npip install graphalama\n```\nOr a developper version with\n```\ngit clone https://gitlab.com/lama-corp/graphalama\ncd graphalama\npython setup.py install -U\n```\n\n## How to use\n\nMost simple pygame applications look like this\n\n```python\nimport pygame\npygame.init()\n\n# Setup of variables, objects...\nstop = False\nscreen = pygame.display.get((400, 400))\n\n# Main loop\nwhile not stop:\n\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n stop = True\n else:\n # Handle inputs, if the user click on some clickable places, buttons...\n # Handle the keys pressed to move players, input text...\n # It's the logic of the game that depends of inputs\n ...\n\n # Then you have an internal logic, applying gravity, running AIs, anything that changes itself every frame\n\n # And finally you render everything with some more or less advanced technics\n\n screen.fill((255, 255, 255))\n\tpygame.display.update()\n```\n\nFor any widget you need to have at least 3 parts in the code to implement it: creation, handling the input, and rendering it. Some widget can have an internal logic going like clock or timer but we'll come back on that later.\n\nSay you want to add a button in your window. A big green play button. We reduce each step to the minimun.\n\n- Creation :\n `play_button = Button(\"PLAY\", bg_color=GREEN, function=play)`\n- Input handling (clicks):\n `play_button.update(event)`\n- Rendering: `play_button.render(screen)`\n\nA minimal hello world would look like this:\n```python\nimport pygame\nfrom graphalama.widgets import *\n\npygame.init()\n\nscreen = pygame.display.set_mode((800, 500))\n\n# creation\nhello_text = SimpleText(\"Hello World!\")\n\nwhile True:\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n quit()\n # a text doesn't change on input so we don't need to update it\n\n screen.fill((255, 255, 255))\n hello_text.render(screen)\n pygame.display.flip()\n```\n\n## Customisation\n\nBefore knowing how to cutomise your widgets so they match your style, we have to understand what *is* a widget.\nA widget is made of three things:\n - a **Shadow**: optional, it provides a nice depth to our application and accentuate our widgets\n - a **Shape**: defines the shape of the background. It also defines the borders, the size and where you can click/select the widget. To list a few common: Rectangle, Circle, RoundedRect...\n - a **content**: the information of the widget, it can be the widget's own content or a child widget (did you know that we can put any widget inside a Button ?)\n\nThose three layers are mixed together to create the widget. To customise our widgets we can therefore easily change one of those three layers.\n\n### Common parameters\n\nFirst, let's have a look to the common parameters that aren't part of the shadow, shape or content.\n\n#### Position\n\nWith graphalama, as with pygame a position is a couple of integers, (0, 0) being the topleft corner and `(x, y)` being the `x`-st pixel on the `y`-st line of the screen.\nEvery time we'll need a position as an argument for a function it will be a tuple `(x, y)` of integers.\n\nGraphalama has a powerfull positioning system for the widgets, whose goal is to be able to design resizable applications witout more effort.\nA widget's position is defined by two elements: its coordinates `pos` and its `anchor`. The `anchor` defines where the widget is anchored,\nthat is, where it will stay when the window is resized and where it will be first put on the screen.\n\nFor instance, if the anchor ia `TOPLEFT`, the widget will always stay at the same distance of the top and the left of the screen, no matter how the window is resized.\nIts `pos` will then be the topleft corner of the widget. This is the default anchor, so we can place our widgets like we would do in most frameworks.\n\nBut say, we want a widget to always stay on the right side of the screen (like a \"next\" button), we just need to set the anchor to `RIGHT`\nand our widget will stay at say 5 pixels from the right border even if we resize the window. Here `pos` will be the middle point on the right\nof the widget. Here's a small drawing to explain it:\n\n![](assets/right_anchor.png)\n\nThis button was created in a 800x500 window with\n\n```python\nButton(\"Next ->\", quit, (770, 250), RoundedRect((200, 100)), bg_color=GREEN, anchor=RIGHT)\n```\n\nIf we resize the window, it will always stay 30px from the right edge.\n\nTwo conclude, there are four things to remember:\n - We can anchor a widget to one or more side of the window by setting the anchor to `RIGHT`, `LEFT`, `TOP` and `BOTTOM`.\n Those constants are defined in `graphalama.constants`.\n - We can combine the anchors with the pipe symbol, `|`, so we anchor a widget to the top right corner with `anchor=TOP|RIGHT`\n - Not only the position, but also the size can be controled with anchors. If `anchor=LEFT|RIGHT`, the distance from the widget\n to both side wil stay constant. Therefore the width will stretch if the window gets bigger and shrink if the window gets smaller.\n - The `pos` of a widget always reflect the anchor: if the anchor is `BOTTOM|RIGHT` the `pos` will be teh bottom right of the widget.\n If it is `LEFT`, `pos` will be the midleft of the widget. However we can always get the topleft of the widget with `widget.topleft`.\n `widget.x` and `widget.y` also work.\n\n That's everything for a very technical part, but it gets very intuitive once we get used to it and saves a lot of time.\n\n#### Color\n\nGraphalama has a great range of options for coloring widgets. No more of the common monochromatic widgets without transparency!\n\nUsually widgets have three colors:\n - `color`, the foreground color, ie. the text of a button\n - `bg_color`, the background color, that's how the shape is filled\n - `border_color`, the color of the border\n\nThose three colors accepts different types, and you can pass any of them at any time:\n - a RGB or RGBA tuple of integers between 0 and 255, you can find a lot of pre-defined colors in `graphalama.constants`\n - a `Gradient` from one color to another (both can be RGB or RGBA)\n - a `MultiGradient` to have a multicolored gradient\n - a `ImageBrush` to draw an image\n - a `ImageListBrush` to draw multiple images and swap between them.\n\n![Example of differents colors and transparency](assets/color_example.PNG)\nYou can get the code for this example [here](assets/color_example.py).\n\nWhat actually is a color ?\nIt is an object with a `paint` method that takes a `Surface` and colorize it.\n\n##### RGB or RGBA tuples\nTuples like `(R, G, B)` or `(R, G, B, A)` are both valid colors, with `0 <= R, G, B, A <= 255`.\nThey are automatically converted to a `Color` object for ease of use. And as expected, they fill the whole area with the same color.\n\n##### Gradients\nA `Gradient(start, end, horizontal)` will fill a shape with a linear interpolation between the two colors.\n`start` and `end` must be two tuples and if `horizontal == False`, the gradient will be drawn verticall,\nso `start` will be at the top of the shape and `end` at the bottom.\n\n##### Multigradients\n ):\nA `Multigradient(*colors, positions=None, horizontal=True)` is like a `Gradient` but with more than two colors.\n\nExample for an equaly spaced blue-yellow-orange-red gradient:\n```\nfrom graphalama.constants import BLUE, YELLOW, ORANGE, RED\nMultiGradient(BLUE, YELLOW, ORANGE, RED)\n```\n\nYou can also choose where the color points are. Here the orange-red part\nwill take the left half of the gradient whereas the blue-yellow and yellow-orange\nwould take only a fourth. The positions are between 0 and\n```\nMultiGradient(BLUE, YELLOW, ORANGE, RED, positions=(0, 1/4, 1/2, 1))\n```\nOf course, the number of positions must match the number of colors, but the positions do nat have to start at 0 and\nend at 1. For instance is the positions are `(1/2, 2/3, 1)`, the first half of the surface will be exactly of the first color.\n\nIf `horizontal == False`, then the gradient is drawn top to bottom and not left to right.\n\n\n### Custom Shape\n\nLet's start again with our play button: `Button(\"PLAY\", bg_color=GREEN, function=play)`.\nThe default shape is a `Rectangle`, So that's what it would look like:\n![](assets/shape_simplest.PNG)\n\nBut you're not limited to rectangles, you can have a rounded rectangle, a circle\nor even any parametric shape or any custom shape (we'll come back on creating your custom shapes later)\n\n![](assets/shapes_examples.PNG)\n\nYou can get the code for this example [here](assets/shapes_example.py).\n\n\nThere are quite a few things to note here.\nFirst of all, if we don't precise the position of the widgets, the will just stack verticaly n the center of the screen.\nThen, we can give any shape to a widget. Every widget can have any shape, we just need to pass it as the `shape` argument in the object initalisation.\nShapes are found in `graphalama.shapes`, they all accept the same parameters :\n - First the `size` of the widget, if none is given the widget will just fit its content\n - Then the argments for the specific shape, ie. the rounding of the rectangle, the equations of the parametric curve...\n - The `border` comes next, which specifies the width of the widget's border\n - Finally comes `min_size` and `max_size`, those are the minimum and maximum size the widget can take if the window is resized\n\n Finally, a shape object is a container for all the information about the size, border, shape.\n If we want to change the size of a widget at runtime, we need to set ` widget.shape.size`, `widget.shape.height` or `widget.shape.width`.\n\n > Therefore a shape can be set only to ONE widget. Widgets can not share references to the same shape.\n\n### Custom content\n\nThere's gonna be some heavy work there, so I wont comment on the current system.\n\n### Custom shadow\n\nShadows put a highight on our widgets, by creating a deeper contrast between the widget and the background.\nShadows are fond in `graphalama.shadows` and they are optional: you can pass `NoShadow` to any widget and...\nit won't show nor calculate any shadow. Otherwise, a shadow accepts 4 optional arguments. Here's the signature\n\n ```python\nShadow(dx=2, dy=2, blur=2, strength=100)\n```\n\nThe two firsts are the offset between the widget and the shadow,\nthey shift the shadow by `dx` and `dy` to the right and down respectively.\n\nOptionnaly, you can blur the shadow, for a smoother result.\nIf blur is 0 the shadow will have the same shape as the widget with the same sharp borders.\nIf blur is positive, then a gaussian blur si applied to the shape. Note that this requires pillow.\nIf you don't have pillow installed, it won't blur the shadow, without raising any exception.\n\nThe strength is an integer between `0` and `255`, it's how dark the shadow is.\n\nHere's an example from [shapes_example](assets/shapes_example.py), where the widgets are\n\n```python\nwid = WidgetList([\n Button(\"Random Shadow\", change_shadow, (400, 250), RoundedRect((400, 250), 50, 1, 2),\n bg_color=(150, 232, 230), border_color=NICE_BLUE, shadow=NoShadow(), anchor=ALLANCHOR),\n Widget((55, 35), RoundedRect(), bg_color=Monokai.PINK, anchor=TOP),\n Widget((150, 35), RoundedRect(), bg_color=Monokai.BLUE, shadow=Shadow(5, 5, 0), anchor=TOP),\n Widget((245, 35), RoundedRect(), bg_color=Monokai.ORANGE, shadow=Shadow(-5, 5, 10, 200), anchor=TOP),\n Widget((340, 35), RoundedRect(), bg_color=Monokai.GREEN, shadow=Shadow(5, 5, 5), anchor=TOP),\n Widget((435, 35), RoundedRect(), bg_color=Monokai.YELLOW, shadow=Shadow(0, 0, 10), anchor=TOP),\n Widget((530, 35), RoundedRect(), bg_color=Monokai.PURPLE, shadow=Shadow(5, 5, 0, 200), anchor=TOP),\n Widget((625, 35), RoundedRect(), bg_color=Monokai.BROWN, shadow=Shadow(-2, -2, 5), anchor=TOP),\n Widget((720, 35), RoundedRect(), bg_color=Monokai.BLACK, shadow=Shadow(5, 20, 5), anchor=TOP),\n SimpleText(\"Shadow(dx, dy, blur, strength)\", (400, 490), anchor=BOTTOM)\n ])\n```\n\n![](assets/shadow_example.PNG)\n\n## Other elements\n\n### Animations\n\n### Drawings\n\n### Font\n\nThere's gonna be some heavy work there, so I wont comment on the current system.\n\n## Widgets\n\n### Button\n\n### SimpleText\n\n## Tips\n\n### The `Pos` class\n\n## Creating your own stuff\n\n### Widgets\n\n###\n\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "", "keywords": "pygame widget widgets gui llama", "license": "", "maintainer": "", "maintainer_email": "", "name": "graphalama", "package_url": "https://pypi.org/project/graphalama/", "platform": "", "project_url": "https://pypi.org/project/graphalama/", "project_urls": null, "release_url": "https://pypi.org/project/graphalama/0.0.1rc0/", "requires_dist": [ "pygame" ], "requires_python": "", "summary": "Easy to use widgets for pygame", "version": "0.0.1rc0" }, "last_serial": 4669255, "releases": { "0.0.1b0": [ { "comment_text": "", "digests": { "md5": "9db5a48423f142b625107b1b4c39fe73", "sha256": "2fb8b620605c0bbe02e1f61585f0a5b4fbfe3898a8628ffe0f24b0c12d1901ac" }, "downloads": -1, "filename": "graphalama-0.0.1b0-py3-none-any.whl", "has_sig": false, "md5_digest": "9db5a48423f142b625107b1b4c39fe73", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 27448, "upload_time": "2018-12-28T01:24:40", "url": "https://files.pythonhosted.org/packages/22/aa/ab3bcbbdd842bc4046cbcafbe9b17b893a5514b3fae0e8dd92b68f80f77b/graphalama-0.0.1b0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "208f45b419bc1f50ce34a991b50e10eb", "sha256": "c2238bcb1e54f74ad5bcb869abe6eb69bc02588dc55b53ab41fa26c6370dc00d" }, "downloads": -1, "filename": "graphalama-0.0.1b0.tar.gz", "has_sig": false, "md5_digest": "208f45b419bc1f50ce34a991b50e10eb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27729, "upload_time": "2018-12-28T01:24:42", "url": "https://files.pythonhosted.org/packages/93/f2/9148df65d10f216733f0dcc67b846cc26b1fe7d6a37a58b51aa2f0a02f43/graphalama-0.0.1b0.tar.gz" } ], "0.0.1rc0": [ { "comment_text": "", "digests": { "md5": "87dfbe276fd922070216da68d37b82d0", "sha256": "2a4f277e239eb0807919ef4ec32270e4212b0a8ed8d50beec27b536900d5cdc6" }, "downloads": -1, "filename": "graphalama-0.0.1rc0-py3-none-any.whl", "has_sig": false, "md5_digest": "87dfbe276fd922070216da68d37b82d0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 30612, "upload_time": "2019-01-07T16:19:07", "url": "https://files.pythonhosted.org/packages/ce/1c/953a91ad93aa2f92cafb9cc2547a99774daa7a48fdd9c11d371bc61fac08/graphalama-0.0.1rc0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7360ee65bc018793ea936159fc75425f", "sha256": "2293e2f3a6f8ea15cc4cee4a008119c095af9db43f01f33c55c4c275fed208f7" }, "downloads": -1, "filename": "graphalama-0.0.1rc0.tar.gz", "has_sig": false, "md5_digest": "7360ee65bc018793ea936159fc75425f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31294, "upload_time": "2019-01-07T16:19:09", "url": "https://files.pythonhosted.org/packages/8b/35/fc9359176b67d523d3434e317210a7908ee750286bab5816c8f83f1f7b49/graphalama-0.0.1rc0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "87dfbe276fd922070216da68d37b82d0", "sha256": "2a4f277e239eb0807919ef4ec32270e4212b0a8ed8d50beec27b536900d5cdc6" }, "downloads": -1, "filename": "graphalama-0.0.1rc0-py3-none-any.whl", "has_sig": false, "md5_digest": "87dfbe276fd922070216da68d37b82d0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 30612, "upload_time": "2019-01-07T16:19:07", "url": "https://files.pythonhosted.org/packages/ce/1c/953a91ad93aa2f92cafb9cc2547a99774daa7a48fdd9c11d371bc61fac08/graphalama-0.0.1rc0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7360ee65bc018793ea936159fc75425f", "sha256": "2293e2f3a6f8ea15cc4cee4a008119c095af9db43f01f33c55c4c275fed208f7" }, "downloads": -1, "filename": "graphalama-0.0.1rc0.tar.gz", "has_sig": false, "md5_digest": "7360ee65bc018793ea936159fc75425f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31294, "upload_time": "2019-01-07T16:19:09", "url": "https://files.pythonhosted.org/packages/8b/35/fc9359176b67d523d3434e317210a7908ee750286bab5816c8f83f1f7b49/graphalama-0.0.1rc0.tar.gz" } ] }