Features
- It is now possible to draw bitmap images on a
Canvas. (#995) - The
DetailedListwidget on Windows has been massively improved, and now matches the visual appearance on other platforms. (#2110, #4319) - Widget implementations are now contributed by entry points, allowing lazy loading on a per-widget basis. (#2687)
- Toga's WinForms backend can now be used on ARM64 machines with a native ARM64 Python interpreter. (#2782)
- The GTK4 backend now integrates with libadwaita for ActivityIndicator, Window, and App. (#3069)
- Toga Positron now has a bootstrap for FastAPI-based websites. (#3327)
- The
WebViewwidget now supports an on_navigation_starting handler to prevent user-defined URLs from being loaded (#3442) - The Qt backend now has implementations for all widgets, plus support for dialogs, fonts and status icons. (#3914)
- The currently active backend can now be retrieved at runtime using
toga.backend. (#3923) - Android apps now support the use of
webbrowser.open(). (#3932) - The
on_webview_loadhandler is now supported on Android (#4036) - Apps built with Toga no longer requires the "Requires Full Screen" key in the app template, allowing support for multitasking on iPadOS. (#4043)
- The columns of
TableandTreewidgets can now be specified usingColumnobjects that provide a richer interface for configuring data access. (#4091) - The header row of a
TableandTreewidget can now be hidden. (#4091) - The
rgbandhslcolor representation classes now declare slots, reducing memory usage. (#4136) - The
Canvaswidget can now draw rounded rectangles. (#4161) - The Table widget on WinForms can now display icons in all columns. Previously, icons were only supported in the first column. (#4164)
ListSourceandTreeSourcenow allow mapping-based data to be used without explicitly providing accessors. (#4221)- The web backend now uses WebAwesome instead of Shoelace to provide web components. (#4227)
- The
Switchwidget is now supported in the Textual backend. (#4230) - The
Treewidget is now supported in the Windows backend. (#4235, #4360) - macOS and iOS apps can now use any font that has been registered with the operating system. (#4307)
- The
Canvaswidget now hassaveandrestoremethods, and supports setting the drawing context attributesfill_style,stroke_style,line_width, andline_dash. (#4332) - The Toga repository now has an
AGENTS.mdfile and Spec Kit constitution to provide assistance for Generative AI tools. (#4344)
Bugfixes
- The
Canvaswidget on Android, Qt and WinForms now matches the behavior of the HTML Canvas when a transform is applied while preparing a path. (#2206) - Calling
stroke()orfill()in aCanvascontext no longer clears the current path. (#2207) SplitContainersin a non-primary tab ofOptionContainerwill now correctly apply its split on Cocoa. (#2288)- The key event handling code now supports non-US keyboards better on macOS. More keys are supported on Qt. (#2428)
- Memory leaks for all remaining widgets have been resolved on all leaking platforms. (#2849)
- Apps no longer crash if an icon file exists but is cannot be loaded. Toga now logs a warning and falls back to a default icon. (#3565)
- When creating an
Imagefrom a file path, it's now guaranteed that the file won't remain open after construction. (#3730) - On Android,
DetailedListnow uses theme-resolved text colors (Primary/Secondary) instead of hard-coded black, fixing unreadable text in dark mode. (#3751) - Calling
scroll_to_bottom()on aMultilineTextInputthat is already at the bottom of the scroll area no longer causes a "bounce" in the scroll position. (#3872) - Double-clicking on the header or an empty row a macOS
Tableno longer triggers the activation of the last item, raising an error if there is no data. (#3905) - The text color of
TextInputon macOS in dark mode has been fixed. (#3919) - When adding or removing tabs from an
OptionContainer, or when setting the content of aSplitContainer, thewindowandappproperties of the content, and the App and Window's widget registry, are now correctly updated. (#3929) - Nested
OptionContainerswill now show label text correctly on iOS 26+. (#3949) - On iOS, the height of the top status bar will now be accounted for properly when the device is rotated. (#3957)
- Apps now log an error instead of crashing if the system locale value is set to an unknown or invalid value. (#3984)
Label,Box, andImageViewwidgets will now display with a transparent background on the Qt backend. (#3997)NumberInputvalues on macOS no longer visually disappear when the widget loses focus. (#3998)- Cocoa and GTK
OptionContainerwidgets now rehints properly to accommodate for all of its content sizes at all times, in addition to the decorations around them. (#4010) OptionContainerandScrollContainerwidgets inside anOptionContainerwill no longer error on layout on Cocoa. (#4010)- Setting an item in a
ListSourcenow gives a "change" instead of an "insert" notification. (#4029) - Data source listeners are now fully disconnected when data changes in
DetailedList,Selection,TableandTreewidgets. (#4030) - On Cocoa, ineffective scrolls in an inner
ScrollContainerwill now be automatically passed on to the outerScrollContainer. (#4034) - Cocoa
ScrollContainerwidgets will now handle elastic effects in small contents properly in a fashion similar to native apps. (#4034) - There are now different
Listenerprotocols forValueSource,ListSource, andTreeSource. (#4035) - Any
AttributeErrorgenerated by data sourceRowandNodeobjects now reference the correct attribute name. (#4037) - GTK4's
DateInputnow consistently emits signals on programmatic change, even when only the year component is altered. (#4040) MainWindowobjects on iOS will no longer have their content overlap slightly with the navigation bar. (#4043)- The
ListListenerandTreeListenerprotocols no longer incompatibly override theinsert,removeandclearmethods ofListSourceandTreeSource, permitting mutable sources which are also listeners. (#4046) - WinForms buttons with icons will now reliably scale to 32x32px icon size, regardless of the size of the original icon image. (#4051)
Screen.as_imagenow properly accounts for HiDPI scaling on Winforms. (#4051)- Large static content can now be loaded into
WebViewwidgets on Windows, Android and Qt. (#4062) - The initial layout of a
MainWindowbefore resize will now be based on the correct size of the container. (#4069) - Window state transitions to
MAXIMIZEDfromPRESENTATIONorFULLSCREENwill now work reliably with the Qt backend. (#4069) - The list of accessors for creating rows in
TableandTreewidgets is now set at widget creation time, preventing inconsistent data conversion if columns are changed. (#4071) - Qt windows will now properly close when a close is requested on the application. (#4078)
- File reference handling in the Android event loop has been corrected. (#4083)
- On Cocoa, when not setting a background color,
DateInput,TimeInput, andMultilineTextInputnow paints the proper background. (#4099) - On Cocoa, setting the background color from non-transparent colors to transparent now works correctly on the
SelectionandMultilineTextInputwidgets. (#4099) - Previously, it was documented that setting the colors for
Selectionwould not work on Cocoa; however, the background color worked partially, coloring an entire rectangular widget instead of the widget itself. The color handling is now entirely removed forSelection. (#4099) - There are no longer any zero division errors when drawing an ellipse in a
Canvason macOS, iOS or GTK backends. (#4161) - The Android implementation of
Canvasnow has the same default corner-mitering threshold as the HTML canvas specification. (#4162) - The mouse wheel scrolling behavior of
MultilineTextInputhas been improved. (#4222) - Entering presentation mode with multiple windows now correctly puts all windows into presentation mode, not just the last one. (#4233)
- In Light Mode on macOS, when a
DetailedListis not focused but has a selection, the text now draws dark instead of light to preserve contrast. (#4264) - To better match native styling, the focus border on macOS
DetailedListhas been removed. (#4270) - Right-aligned, multi-line strings that contain an empty line are now correctly sized on macOS. (#4315)
Canvasnow consistently handles line-dash patterns of an odd or zero length. (#4334)- App-level dialogs on macOS 26 are now reliably responsive to clicks for dismissal. (#4346)
- Some runtime errors caused by Window event handlers firing as part of the window initialization process have now been silenced. (#4347)
- Toga's lazy-loading mechanism now uses an explicit file encoding. (#4365)
Backward Incompatible Changes
-
The
get_platform_factory()function and backendfactorymodules are deprecated. Widget authors should usetoga.get_factory()instead, and writers of new backends should use entry points to declare the implemented objects. The new factory objects are not modules but instead are lazy namespace objects. (#2687) -
The parsing function
travertino.colors.color()(also accessible astoga.colors.color()) is deprecated. The Travertino method has been renamedtravertino.colors.Color.parse(). There should be no need to use this method in Toga, as all APIs that accept colors will automatically parse of raw color representations from strings. (#3946) -
Sourceobjects now look for methods with names of the formsource_{notification}, rather than just{notification}when thenotifymethod is called. If you have a custom listener class with methods likechange,insert,removeorclear, you should re-name them to have asource_prefix:source_change,source_insertand so on. (#4046) -
When nesting stroke contexts or fill contexts for
Canvasdrawing operations, leaving an argument (e.g.color) blank on an inner context now respects any value set on the outer context, instead of resetting it to the default. (#4057) -
The
Canvaswidget has undergone some significant internal changes.- Drawing methods can now be called directly on a
Canvas. Calling them on states is now deprecated. - The "camel case" context manager drawing methods (
ClosedPath,Fill, andStroke) are deprecated. They are now unified with their standalone counterparts (close_path,fill, andstroke, respectively). For example, thefillmethod (lowercase) can be used as a normal method or aswith canvas.fill():. - List-like methods on states are deprecated. Manipulate their
drawing_actionslists directly, and manually callredraw()on theCanvas. - Calling
redraw()on states is deprecated. CallCanvas.redraw()instead. - States no longer hold a reference to their
Canvas; theircanvasattribute is deprecated. (This is largely an internal detail, and unlikely to affect user code.) - The class
toga.widgets.canvas.Contexthas been renamed fromContexttoState. Context'sContext()method has also been renamed tostate().- The
contextproperty ofCanvashas been renamed toroot_state. toga.widgets.canvas.DrawingObjecthas been renamed fromDrawingObjecttoDrawingAction. This is an internal class, and is unlikely to be used directly.
The previous names and APIs should still work, but will raise a
DeprecationWarningif used. See the [upgrading guide][canvas-0-5-4-upgrade] for more details on how to updateCanvasusage. (#4082, #4159) - Drawing methods can now be called directly on a
-
Instances of the
WriteTextandDrawImageobjects representingCanvasactions now reportNonewhen queried for their attributes that haven't been set, instead of supplying the default. (#4089) -
Using
headingsas a keyword argument when creatingTableandTreeobjects is deprecated. Anyheadingsargument should be replaced withcolumns. The use ofheadings=Noneto hide the header row has been deprecated; useshow_headings=Falseinstead. (#4091) -
Specifying
accessorswhen creatingTableandTreewidgets is deprecated. Use ofaccessorarguments oninsert_column()andappend_column()methods has also been deprecated. Useaccessorarguments on column objects or data sources instead. (#4091) -
The behavior of the
Canvaswidget when a drawing was scaled by a factor of 0 in either axis was unspecified and varied across backends and HTML Canvas implementations. TheCanvaswidget now follows a consistent, reasonable behavior when this happens which should produce similar results on all backends. On some backends, to avoid errors or other drawing problems, a very small scale factor is used instead of 0 when asked to scale by 0. (#4110) -
The specification for
Tree/Tablecolumn data has historically documented that an icon in a column is specified with a 2-tuple. However, on some platforms, the implementation has allowed n-tuples and/or other collection types. This has now been constrained - a 2-tuple is the only way to specify an icon for column data; and using a tuple of any length other than 2 will raise an error. (#4135)
Documentation
- Documentation has been added for colors. (#3568)
- The "Success Stories" page has been reformatted into a structured table with consistent fields for platform support, screenshots, descriptions, and BeeWare components. (#3596)
- The API reference documentation has been restructured. (#3941)
- A new contribution guide has been added. (#3969)
- Data source topic guide now includes a discussion of how and when to connect and disconnect Listeners from Sources. (#4030)
- The API design guide now references the BeeWare code style guide. (#4231)
- The FAQ has been updated with entries about file access. (#4239)
- Known limitations on the usage of
OptionContaineras nested content on mobile platforms are now documented. (#4297) - The
Canvasdocumentation has been revamped, with the existing content splitting into two pages (general reference and advanced usage), plus the addition of a migration guide for the new API changes. (#4362)
Misc
- #3685, #3819, #3861, #3923, #3928, #3942, #3944, #3945, #3948, #3951, #3952, #3953, #3954, #3955, #3963, #3967, #3968, #3975, #3977, #3978, #3979, #3980, #3981, #3982, #3983, #3988, #3991, #3993, #4000, #4001, #4002, #4003, #4005, #4019, #4023, #4024, #4025, #4033, #4041, #4046, #4050, #4052, #4055, #4056, #4057, #4058, #4068, #4075, #4085, #4086, #4094, #4095, #4096, #4097, #4100, #4103, #4104, #4105, #4108, #4109, #4115, #4116, #4117, #4118, #4119, #4120, #4121, #4122, #4123, #4124, #4125, #4126, #4127, #4128, #4129, #4130, #4131, #4132, #4141, #4142, #4144, #4145, #4146, #4147, #4148, #4149, #4150, #4151, #4152, #4153, #4154, #4155, #4157, #4160, #4160, #4160, #4162, #4166, #4168, #4169, #4170, #4171, #4172, #4173, #4174, #4175, #4177, #4178, #4179, #4180, #4181, #4182, #4183, #4184, #4185, #4186, #4192, #4193, #4194, #4195, #4196, #4197, #4198, #4207, #4209, #4210, #4212, #4213, #4214, #4215, #4217, #4217, #4224, #4225, #4234, #4240, #4241, #4242, #4243, #4244, #4245, #4246, #4247, #4248, #4249, #4250, #4251, #4252, #4253, #4254, #4255, #4257, #4266, #4267, #4268, #4269, #4272, #4274, #4280, #4281, #4282, #4283, #4284, #4285, #4286, #4287, #4288, #4289, #4290, #4291, #4292, #4293, #4294, #4295, #4308, #4309, #4310, #4311, #4312, #4313, #4316, #4321, #4322, #4323, #4324, #4325, #4326, #4328, #4330, #4333, #4336, #4337, #4341, #4345, #4350, #4351, #4352, #4355, #4361, #4367, #4370