Write a post

Texture management in Kivy using atlas

Published Jun 02, 2017
Texture management in Kivy using atlas

Kivy is an open source, cross-platform Python framework for the development of applications that makes use of innovative, multi-touch user interfaces.


What will you learn in this post?

We will look at how to use atlas files to manage textures in kivy and creating one of our own.

Some resources for you: Atlas: Kivy Documentation, Kivy wiki: Theming Kivy, Oreilly's theming in kivy

What is atlas file?

Atlas manages texture atlases: packing multiple textures into one. With it, you reduce the number of images loaded and speedup the application loading.

An Atlas is composed of 2 or more files:

  • a json file (.atlas) that contains the image file names and texture locations of the atlas.
  • one or multiple image files containing textures referenced by the .atlas file.

Source

If you want a Material design feel for your application and need theming already taken care for you, then I suggest you to look at KivyMD.

Content

  • Creating your own atlas file.
  • Let's dive into code.

What do we have? Download the code for this post from here.

Screen Shot 2017-06-02 at 7.27.31 AM.png

What we want.

enter image description here


Creating your own atlas file

Source for theme files: Themes

cd to the folder where you have all the images you want to create an atlas of then type the following command in the terminal.

python3 -m kivy.atlas myatlas 256x256 *.png

defaulttheme-0.png Red theme Original source

enter image description here

defaulttheme.atlas

{"defaulttheme-0.png": {"progressbar_background": [391, 223, 24, 24], "tab_btn_disabled": [279, 127, 32, 32], "tab_btn_pressed": [381, 127, 32, 32], "image-missing": [249, 167, 48, 48], "splitter_h": [155, 113, 32, 7], "splitter_down": [501, 249, 7, 32], "splitter_disabled_down": [504, 127, 7, 32], "vkeyboard_key_down": [2, 34, 32, 32], "vkeyboard_disabled_key_down": [415, 127, 32, 32], "selector_right": [248, 219, 55, 62], "player-background": [2, 283, 103, 103], "selector_middle": [191, 219, 55, 62], "spinner": [235, 72, 29, 37], "tab_btn_disabled_pressed": [313, 127, 32, 32], "switch-button_disabled": [277, 287, 43, 32], "textinput_disabled_active": [372, 322, 64, 64], "splitter_grip": [499, 189, 12, 26], "vkeyboard_key_normal": [36, 34, 32, 32], "button_disabled": [80, 72, 29, 37], "media-playback-stop": [399, 167, 48, 48], "splitter": [501, 77, 7, 32], "splitter_down_h": [121, 113, 32, 7], "sliderh_background_disabled": [87, 122, 41, 37], "modalview-background": [2, 161, 45, 54], "button": [142, 72, 29, 37], "splitter_disabled": [503, 287, 7, 32], "checkbox_radio_disabled_on": [433, 77, 32, 32], "slider_cursor": [2, 111, 48, 48], "vkeyboard_disabled_background": [68, 217, 64, 64], "checkbox_disabled_on": [297, 77, 32, 32], "sliderv_background_disabled": [2, 68, 37, 41], "button_disabled_pressed": [111, 72, 29, 37], "audio-volume-muted": [199, 167, 48, 48], "close": [417, 227, 20, 20], "action_group_disabled": [468, 462, 33, 48], "vkeyboard_background": [2, 217, 64, 64], "checkbox_off": [331, 77, 32, 32], "tab_disabled": [305, 249, 96, 32], "sliderh_background": [130, 122, 41, 37], "switch-button": [322, 287, 43, 32], "tree_closed": [439, 227, 20, 20], "bubble_btn_pressed": [435, 287, 32, 32], "selector_left": [134, 219, 55, 62], "filechooser_file": [174, 322, 64, 64], "checkbox_radio_disabled_off": [399, 77, 32, 32], "checkbox_radio_on": [211, 127, 32, 32], "checkbox_on": [365, 77, 32, 32], "button_pressed": [173, 72, 29, 37], "audio-volume-high": [49, 167, 48, 48], "audio-volume-low": [99, 167, 48, 48], "progressbar": [305, 223, 32, 24], "previous_normal": [483, 127, 19, 32], "separator": [503, 462, 5, 48], "filechooser_folder": [240, 322, 64, 64], "checkbox_radio_off": [467, 77, 32, 32], "textinput_active": [306, 322, 64, 64], "textinput": [438, 322, 64, 64], "player-play-overlay": [126, 395, 117, 115], "media-playback-pause": [299, 167, 48, 48], "sliderv_background": [41, 68, 37, 41], "ring": [358, 402, 108, 108], "bubble_arrow": [70, 56, 16, 10], "slider_cursor_disabled": [449, 167, 48, 48], "checkbox_disabled_off": [469, 287, 32, 32], "action_group_down": [468, 412, 33, 48], "spinner_disabled": [204, 72, 29, 37], "splitter_disabled_h": [87, 113, 32, 7], "bubble": [107, 321, 65, 65], "media-playback-start": [349, 167, 48, 48], "vkeyboard_disabled_key_normal": [449, 127, 32, 32], "overflow": [245, 127, 32, 32], "tree_opened": [461, 227, 20, 20], "action_item": [339, 223, 24, 24], "bubble_btn": [401, 287, 32, 32], "audio-volume-medium": [149, 167, 48, 48], "action_group": [52, 111, 33, 48], "spinner_pressed": [266, 72, 29, 37], "filechooser_selected": [2, 388, 122, 122], "tab": [403, 249, 96, 32], "action_bar": [173, 123, 36, 36], "action_view": [365, 223, 24, 24], "tab_btn": [347, 127, 32, 32], "switch-background": [192, 287, 83, 32], "splitter_disabled_down_h": [468, 403, 32, 7], "action_item_down": [367, 287, 32, 32], "switch-background_disabled": [107, 287, 83, 32], "textinput_disabled": [245, 399, 111, 111], "splitter_grip_h": [483, 235, 26, 12]}}

Let's dive into the code

After you have run the above command you should have got atleast 2 files a .png and a .atlas.

In our example we have 5 files.

Structure

- main.py
- main.kv
- src
  - components/
      - __init__.py
      - CustomButtons.py
      - CustomCheckBoxes.py
  
-textures/
  - theme-blue/
      ...
        - myatlas-0.png
        - myatlas-1.png
        - myatlas-2.png
        - myatlas-3.png
        - myatlas.atlas
      ...
  - theme-orange/
      ...
        - myatlas-0.png
        - myatlas-1.png
        - myatlas-2.png
        - myatlas-3.png
        - myatlas.atlas
      ...
  - red-lightgrey/
      ...
        - myatlas-0.png
        - myatlas-1.png
        - myatlas-2.png
        - myatlas-3.png
        - myatlas.atlas
      ...

let's make some change in our code or you can download it from here.

src/components/CustomButtons.py

from kivy.uix.button import Button

class CustomButton(Button):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # self.background_down = 'atlas://textures/red-lightgrey/myatlas/button_pressed'
        self.background_normal = 'atlas://textures/red-lightgrey/myatlas/button_pressed'

src/components/CustomCheckBoxes.py

from kivy.uix.checkbox import CheckBox


class CustomCheckBox(CheckBox):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.background_down = 'atlas://textures/red-lightgrey/myatlas/button_pressed'
        self.background_checkbox_normal = 'atlas://textures/red-lightgrey/myatlas/checkbox_off'
        self.background_checkbox_down = 'atlas://textures/red-lightgrey/myatlas/checkbox_on'
        self.background_checkbox_disabled_normal = 'atlas://textures/red-lightgrey/myatlas/checkbox_disabled_off'
        self.background_checkbox_disabled_down = 'atlas://textures/red-lightgrey/myatlas/checkbox_disabled_on'

In main.kv file add the following code below <Theming>: class

<ProgressBar>:
    canvas:
        Color:
            rgb: 1, 1, 1
        BorderImage:
            border: (12, 12, 12, 12)
            pos: self.x, self.center_y - 12
            size: self.width, 24
            source: 'atlas://textures/red-lightgrey/myatlas/progressbar_background'
        BorderImage:
            border: [int(min(self.width * (self.value / float(self.max)) if self.max else 0, 12))] * 4
            pos: self.x, self.center_y - 12
            size: self.width * (self.value / float(self.max)) if self.max else 0, 24
            source: 'atlas://textures/red-lightgrey/myatlas/progressbar'

and here we have.

enter image description here

Similarly, you can link different atlases to different widgets.

  • Button: Red
  • CheckBox :Orange
  • ProgressBar: Blue

enter image description here


Conslusion

Thank you for reading — I hope you found this post helpful. If you have any questions, feel free to reach out to me! (More posts)

Discover and read more posts from Kuldeep
get started
Enjoy this post?

Leave a like and comment for Kuldeep

1
Using Docker and Docker Compose for Local Development and Small Deployments
How to Scrape an AJAX Website using Python
Building your first web app using Python/Flask