Giter VIP home page Giter VIP logo

tukaan's Introduction

Tukaan logo

Tukaan

Tukaan is a Python toolkit for creating cross-platform GUI applications


tukaan.github.io Downloads License: MIT Code style: black #StandWithUkraine


We are looking for contributors 😍

Tukaan is already two years old 🎈🎉, but the project is still in early alpha state. Developing such a toolkit requires a lot of design and coding work, and I'm but a single person.

If you like this project and want to get involved, we'd love to see your contribution! Read CONTRIBUTING.md for more.

What is Tukaan?

Tukaan is a GUI toolkit based on Tcl/Tk. Yeah, that’s the same thing that powers Tkinter, but don’t worry, Tukaan is far not as bad as Tkinter.

It is designed to be a modern and pythonic framework that provides everything you need in a GUI application, without having to install all sorts of third-party extensions to accomplish a basic task.

🔶 Tukaan is powerful

With Tukaan you can build whatever you want. It includes a wide variety of widgets, from basic things like tooltips to advanced megawidgets, dozens of options for integration with the operating system, and a bunch of other things that make creating an application even more convenient.

🔶 Tukaan is modern

Tukaan does not try to mimic the look and feel of Motif or Windows 95. You can create interfaces that look native on Windows, macOS and Plasma, or theme it however you like, so the users might actually want to use it. Unlike Tkinter, it has most of the features you expect from a GUI toolkit in the 21st century. No need to spend hours browsing random forums to figure out how to load a custom font file, such basic things are built in already!

🔶 Tukaan is intuitive

Tukaan is pythonic and intuitive, so you don’t necessarily have to look up the documentation every time, you can figure it out for yourself. However, keep in mind that it is not recommended for complete beginners. You need some knowledge of Python, and some sort of experience in GUI programming can also come handy, although that’s not required.


FAQ

Why did you name this project Tukaan?

Tk's logo is a feather, so I wanted to name the project after a bird with T and K in its name. So I came up with tukán (means toucan in english), and simplified it to tukaan.

How do you pronounce Tukaan?

tukaːn

Credits

tukaan's People

Contributors

demberto avatar kittykittykitkat avatar moosems avatar rdbende avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tukaan's Issues

`tukaan.App` is crazy inefficient

tukaan/tukaan/app.py

Lines 56 to 70 in fcf7ff9

self.title = title
self.topmost = topmost
self.transparency = transparency
# i can't figure out why, but mypy says 'size' is read-only
self.size = width, height # type: ignore
self.fullscreen = fullscreen
if theme is None:
theme = (
"clam"
if self.tcl_call(str, "tk", "windowingsystem") == "x11"
else "native"
)
self.theme = theme

$ cat test.py
import tukaan, tkinter, timeit


def asdf():
    _ = tukaan.App()
    _.quit()


def qwer():
    _ = tkinter.Tk()
    _.quit()


print(timeit.timeit(asdf, number=100))
print(timeit.timeit(qwer, number=100))

$ python3 test.py
can't invoke "event" command: application has been destroyed
    while executing
"event generate $w <<ThemeChanged>>"
    (procedure "ttk::ThemeChanged" line 6)
    invoked from within
"ttk::ThemeChanged"
[...] * 99
10.320173018000037  # tukaan
2.983373939999933   # tkinter

without those lines, tukaan is only between 2.9 and 3.3 seconds

Times

  • with tukaan I never got below 2.9 (commented out those lines)
  • with tkinter I never got below 2.7
  • (with teek I never got below 3.3)

Add Frame widget

tukaan.Frame widget

Required widgets: tukaan.ScrollBar

Documentation: ttk_frame(3tk)

Features to be implemented:

  • Built in scrollbars, adjustable by the overflow attribute

Unsupported Platform?

I get this error idk why
tukaan.exceptions.TclError: Serif: Unsupported platform windows-x64

Improve `TextBox`

  • do something with Tag. prev, next range, (i really don't like, how they currently work)
  • more preset tag?

Allow wildcard imports? 🤔

When I create an app with tkinter I normally will start the file with from tkinter import * so it gets rid of the hassle of importing labels and buttons and whatnot. We need to make that compatible and work with Tukaan. Great job on the release by the way!

Rewrite bindings

Implement binding API

Event classes

Helpers

Tests

Font management

I have no better idea than what teek does.

Usually you don't need a named, mutable font object, just an object to specify the widget font, so a tcl namedfont is a total waste of memory. On the other hand it isn't good to have multiple font classes to different tasks.

`ButtonGroup` widget

A group of buttons, similar to RadioGroup. The button labels and callbacks could be specified in a dict, like items={"Text": do_something}.

The leftmost button should have the Left.TButton style, the rightmost Right.TButton, and all the others Middle.TButton (similar stuff when the orientation is vertical), this way it's possible to do, that only the outer buttons have round corners. (I think my forest theme has this feature, but it might be only in one of my local branches).

Add TabView widget

tukaan.TabView and tukaan.TabView.Tab widgets

Requires other widget: tukaan.Frame

Documentation: ttk_notebook(3tk)

Features to be implemented:

  • append tabs
  • remove tabs
  • hide/unhide tabs
  • move tabs
  • select tabs
  • config tabs
  • get selected tab -> property

Feature: Audio stuff

In tukaan.media or tukaan.audio submodule.

TODO:

  • Open sound
  • Play sound
  • Play section of sound
  • Pause sound
  • Stop sound
  • Record sound
  • Save sound
  • Concatenate sounds
  • Insert sounds
  • Insert section of sound
  • Mix sounds
  • Mix section of sound
  • Apply filters to sounds
  • Apply filters to section of sound
  • Cut section of sound
  • Crop to section of sound
  • Reverse sound
  • Reverse section of sound
  • Get length of sound
  • Filters
    • Amplifier
    • Echo
    • FadeIn
    • FadeOut
    • Formant
    • Generator
    • IIR
    • Map
    • Reverb
  • Modify sound
    • Bitrate
    • Number of channels
    • Encoding
    • Length
  • Configure sound reading
    • Bitrate
    • Number of channels
    • Encoding
  • Delete sound object, and clean up memory

Improve tooltip

Tooltip has some issues on Mac and I have some ideas. First and foremost is the usage of the toplevel:

  1. On mac this makes quite a weird illusion and looks pretty bad. I recommend that we use the button idea and that we just position and un-position as it was initially. My picture of the issue is attached.
  2. I believe that the time for scheduling should be halved to 500 ms instead of a whole second. I also removed the schedule to remove the tooltip after a set time because it seems like it could lead to issues for large amounts of text.
  3. Using newlines makes it look janky because its not an actual button. Image is attached
  4. Users should be able to specify which side the tooltip goes too and I think it would be good if the tooltip keeps the same theming
  5. Make sure that the tooltip keeps the font of the owner widget

Proposed code:

    @classmethod
    def schedule(cls, widget: str) -> None:
        cls._can_show = True

        message = cls._widgets.get(widget)
        if message is None:
            return

        Tcl.call(None, ".tooltip.label", "configure", "-text", message)
        cls._after_id = Tcl.call(str, "after", 500, cls._show_cmd, widget)


    @classmethod
    def show(cls, widget: str) -> None:
        if not cls._can_show:
            return

        owner_x = Tcl.call(int, "winfo", "rootx", widget)
        owner_width = Tcl.call(int, "winfo", "reqwidth", widget)
        tip_width = Tcl.call(int, "winfo", "reqwidth", ".tooltip")
        tip_x = owner_x + owner_width // 2 - tip_width // 2

        owner_y = Tcl.call(int, "winfo", "rooty", widget)
        tip_height = Tcl.call(int, "winfo", "reqheight", ".tooltip")
        tip_y = owner_y - tip_height - 5

        if tip_y <= Tcl.eval(int, f"winfo rooty [winfo toplevel {widget}]"):
            tip_y = owner_y + Tcl.call(int, "winfo", "reqheight", widget) + 5

        Tcl.call(None, "wm", "geometry", ".tooltip", f"+{tip_x}+{tip_y}")
        Tcl.call(None, "wm", "deiconify", ".tooltip")

Images:

  1. Screen Shot 2022-07-03 at 9 24 37 PM

2 . Screen Shot 2022-07-03 at 9 38 19 PM

Messageboxes and dialogs

TODO:

  • Messageboxes
  • Filedialogs
    • Open file
    • Save file
    • Select directory
  • Color selection
  • Input dialog
    • String
    • Number
    • Slider
  • Font chooser
    • Native dialogs on Windows and mac
    • Custom font chooser on X11
  • Calendar dialog
  • About dialog
  • Task dialog
  • Progress dialog
  • Notifications
  • Credentials dialog
  • Print dialog
  • Custom dialog API

Implementation:

  • Use KDialog if available
  • Use Zenity if available
  • Use notify-send if available

Add unittests

Ohh, I hate writing tests...

But there are so much bug and I always mess up something, so it'd be useful.

Theming

Theming in Tukaan

System appearance information

The LookAndFeel object

  • system_theme
  • system_colors
tukaan.LookAndFeel.system_theme
# LookAndFeel.system_theme returns:
# - 'dark' or 'light' on macOS and MS Windoze
# - current Gtk theme if available (not yet implememted)

tukaan.LookAndFeel.system_colors
# Returns a namedtuple containing the system colors

Using native themes

  • AquaTheme
  • Win32Theme
  • KolorScheme
  • NativeTheme
from tukaan import App, AquaTheme, GtkTheme, KolorScheme, Win32Theme

app = App()

app.theme = AquaTheme  # macOS only
app.theme = Win32Theme  # MS Windows only
app.theme = GtkTheme  # Tries to use native Gtk 2.0 theme, Linux only
app.theme = KolorScheme  # Uses Clam theme with KDE Plasma colorscheme, needs `kreadconfig5`

Theming with CSS

See #71

  • CssTheme class
  • Css parser
  • Generate SVG images from the css
  • Generate Tcl theme script from the css

Theme collection

Theme collection module with Tcl themes. See first few comments of #74

Add `tukaan.TextBox` widget

tukaan.TextBox widgets

Requires: tukaan.Image

Documentation: text(3tk)

Features to be implemented:

  • all attributes
  • implement peers
  • get
  • delete
  • insert
  • search
  • replace
  • scroll_to
  • tags
  • all tag attribute
  • marks
  • dump
  • line info
  • count
  • fancy index handling
  • auto scrollbars
  • insert from file
  • easy way to embed widgets
  • insert images
  • text getter, setter
  • fancy undo/redo handling

Rethink grid

Implement placing by cell name, like you'd do it in css

  • Done

In css you can do things like this to place an element by grid cell name:

.some__parent {
  grid-template-areas:
      "label button . ."
      "frame frame other other"
      "button_1 button_1 other other";
}

.some__widget {
  grid-area: other
}

This will place the widget in row: 1, column: 2, and will set the column and rowspan.

So in Tukaan instead of this:

some_widget.layout.grid(row=1, col=2, rowspan=2, colspan=2)

you could write this, and cells are already created for the rest of the widgets:

some_parent.layout.grid_cells = [
    ["label", "button", None, None],
    ["frame", "frame", "other", "other"],
    ["button_1", "button_1", "other", "other"],
]
some_widget.layout.grid(cell="other")

Allow to row-, and columnconfigure widgets, by setting size template (like in css)

  • Done

In css

.some__parent {
  grid-template-columns: 1fr 1fr 1fr 3fr;
  grid-template-rows: 0fr 1fr 1fr;
}

In Tkinter

some_parent.columnconfigure(index=0, weight=1)
some_parent.columnconfigure(index=1, weight=1)
some_parent.columnconfigure(index=2, weight=1)
some_parent.columnconfigure(index=3, weight=3)

some_parent.rowconfigure(index=0, weight=0)
some_parent.rowconfigure(index=1, weight=1)
some_parent.rowconfigure(index=2, weight=1)

In Tukaan

some_parent.layout.grid_column_template = (1, 1, 1, 3)
some_parent.layout.grid_row_template = (0, 1, 1)

Tooltips

Can we create a widget that shows text when widgets are hovered over?

Write documentation

This will make it much easier to get started, I didn’t even know this had so many options without looking at the code!

Images for `Button` and `Label`

Implement image support for tukaan.Button and tukaan.Label widgets

Requirement: tukaan._images._image_converter_class

Features to be implemented:

  • images

High DPI support

  • High DPI awareness
    High DPI awareness should be enabled on Windows by default
  • Scaling
    • Implement UI scaling
    • Support SVG based themes
    • Create SVG based sun valley theme (will be in a separate package)

Localization

  • MessageCatalog object
  • Localized internal strings
  • Right to left on non-Windows systems?

Add GitHub CI actions

Would be nice to have:

  • Pyright checks
  • Pytest checks (when we finally have tests lol)
  • Various Flake8 checks
  • Black check
  • Isort check
  • Pypi publisher

AttributeError: partially initialized module 'tukaan' has no attribute 'App' (most likely due to a circular import)

I just follow the example given in ReadMe to try this module at the first time.

import tukaan

app = tukaan.App("My first Tukaan app")

app.run()

Then I get this error.

(env) D:\Desktop\coding\sandbox>d:/Desktop/coding/discordpy/env/Scripts/python.exe d:/Desktop/coding/sandbox/tukaan.py
Traceback (most recent call last):
  File "d:\Desktop\coding\sandbox\tukaan.py", line 1, in <module>
    import tukaan
  File "d:\Desktop\coding\sandbox\tukaan.py", line 3, in <module>
    app = tukaan.App("My first Tukaan app")
AttributeError: partially initialized module 'tukaan' has no attribute 'App' (most likely due to a circular import)

I am new to this module and I have no idea about why would this happens.
Sorry for my incoveniences causes.

Create DockMenu

Important: when using MacOS having a good DockMenu menu is incredibly important. I propose that we create a good system for this as it does not seem to be built into tk. See my stackoverflow question for more detail. This is also an issue for windows so setting up a good system is important to get done at some point.

Create layout managers

The grid LM

widget.layout.grid(row=1, col=1, margin=(1, 2, 3, 4))

Parameters

Parameter Description
row row
col column
rowspan rowspan
colspan columnspan
margin human understandable expression for padx and pady
hor_align horizontal stickiness see below
vert_align vertical stickiness see below
  • Parameters done

Horizontal and vertical alignment (sticky)

Horizontal align Vertical align Tk sticky value
None None
None top n
None bottom s
right None e
left None w
left top nw
right top ne
left bottom sw
right bottom se
stretch top new
stretch None ew
stretch bottom sew
left stretch nsw
None stretch ns
right stretch nse
stretch stretch nsew
  • Alignment done

The position LM

widget.layout.position(x=10, y=10, width=ScreenDistance(4, "cm"))

Parameters

Parameter Description
x x, if you give it in percents, it will be relx
y y, if you give it in percents, it will be rely
width width, if you give it in percents, it will be relwidth
height height, if you give it in percents, it will be relheight
anchor anchor
  • Parameters done

TODO:

In tkinter you can do things like this:

widget.place(relx=1, x=-20)

which will place the widget 20 pixels before 100%, because Tukaan don't supports explicit relative sizes and positions you cant do this. could be solved by a move method
e.g.

widget.layout.move(x=-20)

# and also for grid:
widget.layout.move(row=-2)
  • Move method done

  • Implement info, and other methods (slaves command into the child_stats of the widget )

Upload to pypi soon

Hasn't been updated in a while and I'd like to try some of the new features

Always catch Tcl errors and raise Python exceptions instead

Currently at lot of places Tukaan simply re-raises the errors thrown by Tcl, which aren't very informative, and since Tukaan covers so much of the Tk stuff, they are sonetimes not even relevant.
We need to create appropriate exception classes and raise them in these places with descriptive messages.

Add Entry widget

tukaan.Entry widget

Documentation: ttk_entry(3tk)

Features to be implemented:

  • fancy index handling
  • built in validation for
    • int
    • float
    • email address
    • hex color
    • custom regex
  • parameters
  • everything else

Screen and ScreenDistance may not work at all

Tukaan's Screen and ScreenDistance objects are really nice and useful, but based on this SO question, they may not work at all on dual monitor setups.

Another problem is that Tcl/tk doesn't know the real ppi, only dpi, so ScreenDistance works well only if user doesn't use xrandr --dpi <not ppi>.

Add `CheckBox` widget

tukaan.CheckBox widget

Requirements: Boolean control variable

Documentation: ttk_checkbutton(3tk)

Features to be implemented:

  • select
  • deselect
  • invoke
  • toggle state
  • get if selected
  • set if selected

Add Images

tukaan._images._image_converter_class, tukaan.Image, tukaan.Icon and tukaan.IconFactory classes

Images work only with PIL, because Tk images still suck.

A widget to display images

image = PIL.Image.open("img.jpg")

image_widget = tukaan.Image(root, image)

Can also be used for a button, or anything else

image = PIL.Image.open("img.jpg")

image_button = tukaan.Button(root, image=image)

Icon class WITHOUT PIL, so it's fast, but immutable, only png

icon = tukaan.Icon("icon.png")

icon_button = tukaan.Button(root, image=icon)

IconFactory is basically an object to collect Icons

icons = tukaan.IconFactory(light_theme="./dark_icons", dark_theme="./light_icons")

icon_button = tukaan.Button(root, image=icons.get("new_tab"))
  • Image
  • Icon
  • IconFactory
  • Animated images

TerminalView widget

Terminal-like widget thingy, that allows you to run basic commands.
I don't want it to be a fully functional terminal, as it would require a lot of work, but it'd be useful for running basic commands.

Example usage:

term = tukaan.TerminalView(
    app,
    cwd=Path.home(),
    prompt="{user}@{node}:{cwd}$ ",
    input=True,
    output=True,
    stdin=True,
    stdout=True,
    stderr=True,
)

Move tkdnd to Dropp submodule

TODO:

  • Move tkdnd to Dropp submodule
  • Rename tkdnd to Dropp
  • Improve build system (help needed)
  • Translate Tcl part to Python for easier maintainability
  • Include it in libtukaan

Fonts

Font management in Tk (and in Tkinter too) is a big pile of shitt

In Tukaan it shouldn't be

Add multiple monitor support

Multiple monitors

Add `RadioButton` and `RadioGroup` widget

tukaan.RadioButton and tukaan.RadioGroup widgets

Requirements: control variables

Documentation: ttk_radiobutton(3tk)

Features to be implemented:
RadioButton:

  • select
  • invoke
  • get if selected

RadioGroup:

  • select radio by id (value)
  • destroy radio by id (value)
  • get radio object by id (value)
  • get selected radio object
  • get current value
  • configure items
  • access radio object's id

Create MenuBars

How do I create menubars? Can we make it possible to create menubars before the application window is created in order to have an instant loading of it?

tukaan.exceptions.TclError: Serif: Unsupported platform windows-x64

I cant run any Tukaan code on windows? Help

import tukaan

# Create window
app = tukaan.App("Test TabView widget")

# Create tabview
tabview = tukaan.TabView(app)
tabview.grid()

# Create tabs
tab_1 = tabview.Tab("Tab 1")
tab_2 = tabview.Tab("Tab 2")

# Add tab contents
tukaan.Button(tab_1, "Button in tab 1").grid()  # You can display it inline, but then you can't access the object later
tukaan.Button(tab_2, "Button in tab 2").grid()

app.run()

ScrollView widget

A scrollable frame.

scrollview = ScrollView(
    app,
    overflow=(False, "auto"),
    padding=(1, 2, 3, 4),
)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.