Snu Kivy Template is a collection of classes and widgets that make it easier to create theme-able, clean, and a bit flashy apps in Kivy. Please note that this depends entirely on Kivy, and will not be usable without Kivy installed first.
This is a gift to the Kivy community, a culmination of what I have learned over the years when developing several kivy-based apps. Use these classes as a basis for your own, or just use them directly, I impose no limitations on the code or images enclosed in this archive.
To use this template, copy the 'snu' folder to your app directory, and start importing stuff. See the main.py and test.kv files for examples on how to use the various widgets.
These widgets mostly depend on the 'NormalApp' class found in 'snu.app.NormalApp'. To use the various widgets, you must make your app a subclass of this, not the basic kivy App class.
Here is a demo of some of the features implemented:
This class is a subclass of the 'kivy.app.App' class. Please note that to set the following variables to custom values, you can pass them in when creating and running your app like this:
MyApp(theme_index=1).run()
This class also implements the following extra features:
Two default themes are included in the 'themes' variable, this is simply a list of dictionaries with a specific set of keys. Copy one of the theme variables and modify the color values to create your own.
Numeric Property, this controls the overall scale of interface, sane values should be between 50 and 150.
This value is loaded from the app config file, 'buttonscale'.
When the config is changed, or when this value is changed, the app will automatically adjust scale.
Relative scaling of text, sane values are between 50 and 150.
This value is loaded from the app config file, 'textscale'.
When the config is changed, or when this value is changed, the app will automatically adjust scale.
Option Property, this must be set to either 'divisions' or 'pixels'. This determines how the interface will be scaled for all included widgets. See 'NormalApp.scale_amount' for more information on each option.
Numeric Property. How this is interpreted will vary depending on how the 'scaling_mode' is set. This acts as a multiplier for the button_scale variable. Defaults to 15.
- If scaling_mode is set to 'divisions', this will define the number of buttons that will be vertically visible in the window at a button scale of 100%.
- If scaling_mode is set to 'pixels', this variable will set the height of the standard button in pixels.
A good way to make the interface scale well to different screen sizes is to use pixel scaling mode, and set the value using a function from kivy.metrics, like so:
from kivy.metrics import cm
MyApp(scaling_mode='pixels', scale_amount=cm(1)).run()
Numeric Property, this defines the index of the theme from the 'themes' variable to be loaded on app creation. Override this variable in your app to set a different theme index to start with.
Load a specific theme index from the themes variable. This will cause the theme to 'fade' from the current theme.
Tip: Try creating a fully black or fully white theme as the default, then loading your default theme in your on_start for a nice fade-in!
Load a theme dictionary as the theme for this app. Note that if any variables are missing from the dictionary, the current variables will not be changed.
Numeric property that sets the default width in pixels of auto-generated popups. Defaults to 640.
Boolean Property, defaults to True. Setting this to False will disable all animations in the custom widgets.
Numeric Property, defaults to 0.2. This will define the length of the animations in all custom widgets.
This function will create a quick colored overlay in the shape and size of the passed-in widget. This can be used to bring the user's attention to an important widget, or to show that something has been clicked on.
The 'mode' argument can be set to 'height' to cause the clickfade to fade out by shrinking in height instead of fading out (default behavior).
This function will create a user feedback message that will automatically be displayed by all snu.label.InfoLabel widgets.
This message will blink for a few seconds then vanish.
Pass in a Float to the timeout variable to change the time this text is displayed.
This function will instantly clear the app message shown in the InfoLabel widgets.
This function will open a popup that shows the about this app message.
String Property, this is the text that will be shown in the popup generated by the about() function shown above.
This function will open a simple message popup that displays the passed in String along with a basic 'OK' button.
Keyboard and joystick/gamepad navigation is implemented through some functions in the NormalApp class, and the snu.navigation.Navigation class. To use this functionality, you must first activate it in your app's on_start() function, then you must use classes that utilize the Navigation class as a mixin. Relevant classes in this template include this mixin already (all buttons, all text inputs, slider, smoothsetting and filebrowser list items).
To activate navigation in your app, you must do two things:
- Call one of the built-in start functions to activate it
- Use widgets that mix in the snu.navigation.Navigation class
To navigate between selected items, press the down or up arrow keys (or joystick down or up, or down or up on a gamepad dpad). When an item is selected, it will be highlighted by adding a colored square to the canvas.after commands.
When a widget is selected, press enter, or the first button on the joystick/gamepad to activate the widget (for buttons this will press it, for text inputs this will focus it).
For widgets that can be adjusted with different values such as sliders or smoothsetting widgets, pressing the left/right arrow keys, or left/right on the joystick or gamepad dpad will cause this widget to raise or lower its variable.
For recycleviews with a lot of elements, it can be benefitial to jump out of the list, press the tab key to immediately jump to the next selectable widget out of the recycleview.
Calling this (suggested from your app's on_start() function) will tell the app to start listening to keyboard commands for navigating widgets.
Calling this (also suggested from your app's on_start() function) will tell the app to start listening for joystick commands for navigation.
Boolean Property, defaults to True. Set this to False to disable all navigation keyboard intercepts temporarily. This can be useful if you wish to use the keyboard for something else temporarily.
This function will go to the next selectable item in the widget tree.
This function will go to the previous selectable item in the widget tree.
This function will attempt to activate the 'decrease' function for the current selected widget if there is one.
This function will attempt to activate the 'increase' function for the current selected widget if there is one.
This function will skip to the next recycleview if inside one, otherwise it will go to the next selectable item in the tree.
This function will properly unset the current selected item. Please do not simply set "NormalApp.selected_object = None" as this will not tell the widget it has been deselected.
This is a list containing keyboard or joystick scancodes to use for navigating to the next selectable widget down in the tree. This defaults to arrow key down, joystick down, and dpad down. You can customize your keyboard or joystick controls by changing this list in your app to whatever scancodes you wish.
This is a list containing scancodes to use for navigating to the previous selectable widget in the tree. This defaults to arrow key up, joystick up, and dpad up.
This is a list containing scancodes to use for activating the currently selected widget. This defaults to enter, and the first button on the joystick or gamepad.
This is a list containing scancodes to use for increasing the value of a selected widget that supports this. This defaults to arrow key right, joystick right, and dpad right.
This is a list containing scancodes to use for decreasing the value of a selected widget that supports this. This defaults to arrow key left, joystick left, and dpad left.
This is a list containing scancodes to use for jumping out of a recycleview list of selectable widgets. This defaults to the keyboard Tab key.
This is a numeric property, range of 0-1. This value represents the percentage of the joystick axis that is ignored. Defaults to 0.25.
To have your own classes selectable by the navigation functions, please mix this class into your own like this:
from snu.navigation import Navigation
class MyButton(Button, Navigation):
pass
The navigation functions will also call several functions when navigation related things happen, you may override these function to customize how your widget behaves under keyboard navigation.
-
on_navigation_activate()
This function is called when the widget is selected and the 'navigation_activate' key is pressed. -
on_navigation_increase()
This function is called when the widget is selected and the 'navigation_right' key is pressed. -
on_navigation_decrease()
This function is called when the widget is selected and the 'navigation_left' key is pressed. -
on_navigation_next() This function is called on the selected widget before the next widget in the tree is navigated to. Have this function return True to 'stick' the keyboard navigation to this widget, this is useful for enabling custom navigation of child widgets. When the children have been navigated, have this function return False.
-
on_navigation_prev() This function is called on the selected widget before the previous widget in the tree is navigated to. Have this function return True to 'stick' the keyboard navigation to this widget, this is useful for enabling custom navigation of child widgets. When the children have been navigated, have this function return False.
-
on_navigation_select()
This function is called when a widget is selected. This should not need to be overriden normally, but widgets with custom canvas.after code may have issues with the default function. -
on_navigation_deselect()
This function is called when a widget is de-selected. Like the select function, this should not need to be overriden normally.
Possible Problems:
Note that by default the enter key is the activate key, this can cause problems with multi-line inputs, be ready to change this function, or override the on_navigation_activate for any multiline text inputs.
Extremely complex widget trees, or multi-layer recycleviews may cause problems, I simply cannot test all combinations, please submit a bug report if you have any issues.
A couple of helper functions to assist with saving logs for crashes are included.
To use these functions, you should wrap your main app loop in a try/except like so:
if __name__ == '__main__':
try:
MyApp().run()
except Exception as e:
try:
MyApp().save_crashlog()
except:
pass
os._exit(-1)
Please note that by default, this will only save the most recent crash log, and you are responsible for providing the user a method to view/save this log.
This function will return the default file location for the crash log. This should end up saved in the same folder as your app will save it's settings file.
You can use this function to return the file for saving where the user will have better access to it (or, for instance, to send via email).
Be warned that this file may not exist yet!
This function should be called immediately after the app crashes, it and it will save the kivy log along with any traceback information with the filename returned by get_crashlog_file().
This button will automatically use the current theme's colors for background and text, and will animate between them for nice smooth button presses.
All buttons will default to being app.button_scale height.
All button text will default to being the app.text_scale size.
Boolean Property, setting this to True will cause this button to be the theme's button_warn colors instead of the standard colors.
All buttons are based on this class.
Based on the ButtonBase class, this button will only be as wide as it needs to be to include the shown text.
Based on the ButtonBase class, this button has a size_hint_x of 1.
Similar to the NormalButton above, but also shows a double-arrow graphic to show that this is a dropdown menu.
Similar to the WideButton above, but also shows the double-arrow graphic to indicate that this is a dropdown menu.
Similar to the WideButton above, but using the menu button colors from the theme.
Similar to the NormalButton, but using the toggle button colors from the theme, and implementing toggle button functionality.
Like NormalToggle, but with a size_hint_x of 1
Special button with the 'hamburger' icon and square-shaped. Clicking this button will open the app settings.
Themed widget for DropDown menus, use instead of the standard DropDown class. This also includes a nice opening animation.
All labels will use the theme colors for text color
All labels will default to being app.button_scale height.
All labels' text will default to the app.text_scale size.
Standard label class, label is full width and text will be horizontally centered.
This label will only be as wide as the text is.
Full width label, text will be aligned to the left side.
Larger font size and colored using theme's header_text value for the color.
Special label that is filled with the app.infotext text, will also flash when the text changes.
Label that scrolls text back and forth when the text is larger than the label size. Set 'ticker_delay' to adjust delay in seconds before label scrolls. Set 'ticker_amount' to change the scroll pixel size per frame, this can be less than one for slower scrolling.
Special classes that help with layouting.
Empty widget that is 1/4 the button size in both width and height.
Empty widget that is 1/2 the button size in both width and height.
Empty widget that is the button size in both width and height.
Horizontal BoxLayout that is the button height, uses the headerbg image from the data folder as its background, and is colored based on the theme main_background color.
Similar to the Header class, but with no background or coloring.
Vertical BoxLayout that uses the mainbg image from the data directory as a background, and is colored based on the theme main_background variable.
Popups can be easily created and themed using these classes.
def delete_function(content, answer):
popup.dismiss()
if answer == "yes":
do_delete(content.data)
content = ConfirmPopupContent(text="Are You Sure?", yes_text="Absolutely!", no_text="Wait...", warn_yes=True, data=stuff_to_delete)
content.bind(on_answer=delete_function)
popup = NormalPopup(title="Delete This?", content=content)
popup.open()
Themed popup class using the panelbg image from the data directory and theme's menu_background color.
Basic popup content that has a message and a close button.
Basic popup content that has a labeled textinput and ok/cancel buttons.
Basic popup content that has a message and ok and cancel buttons.
Themed RecycleView class using theme settings for scrollbar size and colors.
Subclass of RecycleBoxLayout that implements selection behavior when paired with RecycleItem subclasses.
Warning: not using a RecycleItem subclass for the viewclass will not allow for selection behavior.
Set the 'multiselect' variable to True to enable multi select mode: Shift-click to select a range of items, Ctrl-click to select multiple items.
Same as SelectableRecycleBoxLayout, but in a gridlayout. By default it will attempt to reflow the number of columns based on a width of 4 times the button scale.
Specialized class that is designed to be mixed with other classes and placed in a recycleview.
This class allows recycleview items to be selected, removed in an animated fashion, and have alternating colors to make rows easier to see.
Subclass of RecycleItem that includes a NormalLabel class, shown as an example for mixing other classes with RecycleItem, and provided for convenience.
Themed subclass of ScrollView, scrollbar will be sized and colored based on theme settings.
Subclass of Scroller, begins in a centered position.
Subclass of Scroller, allows ScrollView clasess to be placed inside of it and still respond to touches. Internal ScrollViews must be added to the 'masks' property, for example:
<ScrollWrapper>:
masks: [subscroller]
Scroller:
id: subscroller
Subclass of ScrollView, removes scrollbars and allows for finer control over touch events.
Set this to True to enable scrolling with the middle mouse button (blocks middle mouse clicks on child widgets).
Set this to True to enable touch 'flicks' to scroll the view (after touch release, scrolling will continue for a while).
Set this to True to enable click-n-drag scrolling within the scrollview itself, stanndard touch-style scrolling.
Set this to True to enable scrolling via the mouse wheel or two-finger swipe scrolling.
ListProperty, add any child widgets to this, and they will receive all touches on them, blocking any touch controlls of this widget within their bounds.
Implements a scrollbar as its own widget, completely separate from the scrollview. This is intended to be used with TouchScroller, but can be used with any ScrollView-based class.
This scrollbar also includes some convencience features like clicking in the open area to scroll to that point, and limiting the minimum size of the scroll control to be no smaller than its width.
Should point to the ScrollView based widget that this scrollbar will control.
Apply a rounding of this number of pixels to the corners of the scroller control.
Will be set to True if the scroll area is large enough to be scrolled.
If set to True, this widget will shrink to 0 width if the scroll area is not large enough to be scrolled
Custom subclass of kivy.uix.slider.Slider, implements a double-click reset function.
A function must be bound to the 'reset_value()' function to allow this to work.
For example, in kvlang:
SpecialSlider:
reset_value: root.reset_function
Themed slider based on SpecialSlider. Uses colors from the theme and the sliderbg image from the data directory.
A widget that displays a navigable file browser layout complete with a sidebar for system folders and shortcuts. Two events are called, on_select and on_cancel when the user clicks the select and cancel buttons.
Due to the many different uses for a file browser, there are a lot of options available to control the behavior of this widget. Unfortunately, some of these options can conflict with each other, so here are some examples.
The default settings are good for opening a single file, just use:
FileBrowser()
To select a folder to export a pre-defined file, use:
FileBrowser(file_select=False, folder_select=True, show_files=False, show_filename=False)
To let the user select a folder to export a file that they define, use (note that you should check the 'edited_selected' value, not 'selected'):
FileBrowser(edit_filename=True, clear_filename=False, file_select=False, default_filename='default.txt')
List Property. This is the files or directories that the dialog selected. Only the filename will be included, not the full path.
String Property. When edit_filename is enabled, and multi_select is disabled, this variable will be set to the text in the filename input field, allowing the user to provide a custom filename.
String Property. This is the folder that the dialog is currently displaying. Set this to start in a specific folder, and read it to find out what folder the user ended up in.
List Property. This is a list of extensions to display. Set it to empty to display all files. This expects standard wildcard style matches, such as:
FileBrowser(filetypes_filter=['*.png', '*.jpg'])
String Property. When the widget is created, the filename field will be set to this value. This can be used to display the filename that will be written, or to give the user a starting point for a filename.
Boolean Property, defaults to True. When this is True, the dialog can be used for selecting files. Note that files will still be displayed by default, unless you hide them.
Boolean Property, defaults to False. When this is True, the dialog can be used for selecting folders. Keep in mind that this will not disable file_select, if you only want to select folders please disable that variable.
Boolean Property, defaults to False. Setting this to True allows multiple files to be selected. Clicking a file will toggle selection, and a range of files can be selected with shift-click. Please note that only one folder may be selected, even if this is set to True.
Boolean Property, defaults to True. Display files in the browser. Setting this to False will result in only folders being shown.
FileBrowser.show_hidden
Boolean Property, defaults to True. Display hidden files when show_files is enabled.
Boolean Property, defaults to True. When this is True, the select button cannot be clicked if no file or folder is selected or provided.
Boolean Property, defaults to False. Setting this to True allows the user to enter a filename manually, or to edit existing filenames. This can only be used when multi_select is disabled. The edited filename will be stored in the variable 'edited_selected', be sure to check this if you wish to use the user's edit.
Be warned: enabling this may result in the 'selected' variable being empty, and only the 'edited_selected' variable containing a valid value.
Boolean Property, defaults to True. When this is True, the filename will be cleared when in file select mode and the folder is changed.
Boolean Property, defaults to False. Setting this to True will cause all files to be selected in the folder when each folder is opened. This variable only works when multi_select is enabled.
String Property, defaults to 'Cancel'. This is the text shown on the cancel button.
String Property, defaults to 'Select'. This is the text shown on the confirm or ok button.
Numeric Property, defaults to 0.5. This is the size_hint_x variable for the shortcuts area on the right side, also controls the width of the ok and cancel buttons.
Boolean Property, defaults to True. Setting this to False will hide the cancel button. Hide this if you have a different method for canceling the file selection.
Boolean Property, defaults to True. Setting this to False will hide the ok button. Hide this if you have a different way of confirming a file selection.
Boolean Property, defaults to True. Setting this to False will hide the new folder and delete folder buttons. Hide these if you do not want the user to modify the folder structure.
Boolean Property, defaults to True. Setting this to False will hide the selected filename field. This may be useful to hide for export dialogs, or for folder selection dialogs.
Class based on kivy's kivy.uix.videoplayer.VideoPlayer class, but meant for playing audio. Includes a stop, play/pause, volume buttons, and a slider for displaying and seeking the song position. Most variables and functions that make sense are ported over from the VideoPlayer, see kivy's documentation for more information on these.
- Variables for setting, seeing the song: source, duration, position, volume, state
- Variables for theme: image_play, image_stop, image_pause, image_volumehigh, image_volumemedium, image_volumelow, image_volumemuted
- Functions: seek()
Subclass of kivy.uix.stencilview that limits touches to the stenciled area only.
All text inputs default to being the standard button height, and are themed based on the theme colors.
Themed TextInput with some standard convenience settings. By default provides no limitations on text entered, implements a right-click/long-press context menu for standard clipboard operations.
Horizontal position (float) from where the underline will grow from. 0 Will result in the line starting on the left, 0.5 from the center, and 1 from the right side.
Time in seconds for the animate in effect.
Time in seconds for the animate out effect.
Color that the input background will be when not active.
Color that the background will fade to when the text input is focused.
Color of the border line around the background.
Thickness of the border line around the background.
Radius of rounded corners on background.
Boolean variable. When set to True, the hint text will animate to the top of the text input and remain visible.
Set this to 'float', 'integer', 'filename' or 'url' to limit allowed characters to those modes. See FloatInput and IntegerInput for more information.
Boolean variable. When allow_mode is set to 'float' or 'integer', this will allow negative numbers when set to True, or disallow when set to False.
This function is called when the 'Enter' key is pressed in the text input field. This function will be passed the textinput widget, and the current text in the widget. You can overwrite the function in your own subclass, or bind it to another function like so:
NormalInput:
press_enter: root.search
Themed TextInput widget that limits inputted text to only numbers and a single period.
Features 'allow_negative' boolean option, set to False to prevent negative numbers.
Themed TextInput widget that limits inputted text to numbers only.
Features 'allow_negative' boolean option, set to False to prevent negative numbers.
This is a touch and mouse-friendly horizontal list selection widget. It is designed to show a scrollable list of elements that can be selected with a swipe, drag, or clicking the left/right buttons. This widget uses the 'Roulette Scroll Effect' class originally from the kivy garden (https://github.com/kivy-garden/garden.roulettescroll) to create a 'snapping' scroll effect.
List Property. This should contain a list of strings that define the names of the elements to show.
Numeric Property, defaults to 0. This is the index number in the 'content' that this widget will display on initialization.
Numeric Property. This is the currently set index of the content list that the selector is set to. Read this value to determine what the user has picked.
NumericProperty, defaults to 1. This is how long in seconds that the left or right button should be held down before it starts being repeated.
NumericProperty, defaults to 0.1. This is the minimum repeat time in seconds that will be accelerated to.
NumericProperty, defaults to the widget's height. This is the width of each element in the list. Be sure to set this higher if you are using longer strings for your content!
NumericProperty, defaults the widget's height. This is the width of the left/right buttons. Setting this to 0 will completely hide and disable the buttons.
String Property. This points to the filename for the image used for the left/right buttons to change the setting. Defaults to a simple arrow.
NumericProperty, defaults to 0.5. This widget has a gradient overlay to fade out the non-selected numbers by default, the transparency of this gradient can be set here. Set to 0 for no gradient, 1 for a very heavy gradient.
Numeric Property, defaults to 10. This is the number of pixels to apply rounding to the corners of the widget, increase this value for a more rounded widget, or set to 0 for a square widget.
Fully themed settings screen that follows the colors of the rest of the app. Implements an 'aboutbutton' settings item that shows a button that opens the app's about popup.