beeware / toga

A Python native, OS native GUI toolkit.
https://toga.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
4.19k stars 656 forks source link

Add widget as table element #841

Open saroad2 opened 4 years ago

saroad2 commented 4 years ago

Expected Behavior

I want to add a table with Toga that one of its columns is a column of switches (checkboxes). When I run the application, instead of putting the checkboxes in the desired column, it writes its representation string. Is there any way you can fix that?

Example code:

data = [
   ["a", "b", c"],
   ["d", "e", f"]
   ["g", "h", i"]
]

table = toga.Table(
    headings=["choose", "1", "2", "3"]
    style=Pack(flex=1),
)

for record in data:
   checkbox = toga.Switch(label="label")
   table.data.append(checkbox, *record)
main_box.add(table)
main_window.content = main_box

Your Environment

freakboy3742 commented 4 years ago

Is it fixable? Maybe. Is it an easy fix? I don't know. I believe this already works on macOS; I have no idea what would be involved in making it also work on Linux or Windows.

saroad2 commented 4 years ago

So I did a little research and found out this.

What I actually needed is a checkbox for every row. I need that in order to select rows from the table in my project.

The question is: how would we use it in Toga? is it relevant for all platforms? I think it is.

My suggestion is to add a boolean checkboxes property to toga.Table. If it's true, add checkboxes for the table rows. Otherwise, do not. Also, we should add the following methods:

freakboy3742 commented 4 years ago

If I'm reading that correctly, the Winforms widget is restricted to only allow a checkbox on a per-row basis? i.e, you can't drop a checkbox anywhere in the layout - it can only be at the start of the row?

If so, that's an interesting restriction. I can definitely see the use case they're aiming for, though - the most likely use case for a checkbox in a table is exactly what you're using it for - "select this item".

However, it poses a bigger question for Toga - do we modify the Toga API to add "selectable rows" as an API, or do we keep looking for a way to include arbitrary widgets in a Winforms table?

saroad2 commented 4 years ago

I think you are right, but I am not familiar with Winforms enough in order to give you an educated answer.

I don't know whether it's right or not to constraint the usage of only checkboxes in tables. Right now this is the only thing that separates me from using the Table widget instead of simply using Box elements order as a table (which is what I actually using at the moment).

I guess in the end it's a question of design if it's appropriate for Toga to handle those things that way.

samschott commented 4 years ago

I believe this already works on macOS;

It works for a Tree widget on macOS which was recently rewritten to be view-based. The Table widget is currently still cell-based but rewriting it should not be too much work with the experience from NSOutlineView. On Windows, this seems to be more difficult. From their documentation:

A ListView control allows you to display a list of items with item text and, optionally, an icon to identify the type of item. For example, the Windows Explorer list of files is similar in appearance to a ListView control.

I think the general use case of arbitrary widgets in a table is nice to have if supported by the platform. Otherwise, putting together an equivalent by combining other widgets may not be worth the effort and can easily look out-of-place. The use case of checkable rows could possibly have its own cross-platform API without sacrificing the flexibility afforded by some platforms.

saroad2 commented 4 years ago

@SamSchott , So you are talking about a new widget named CheckboxedTable that is exactly like Table (and maybe even inherits from that), but also has a checkbox in every row?

This can work, I think.

samschott commented 4 years ago

I was thinking of an API to make rows or items in a Table widget checkable without introducing a new widget altogether. This could be similar to the API of QTableWidgetItem in Qt with properties checkable and checked for every row or item.

But this of course depends on finding out what is available on different platforms, I might well have overlooked something in Winforms.

freakboy3742 commented 4 years ago

In terms of a Toga API, I'm not wild about the idea of CheckboxedTable - that sounds like a workaround to compensate for the fact that the Windows API is proving difficult.

I agree with @SamSchott that allowing any table cell to be an interactive checkbox (or, I guess, any other simple control) is the real goal. In that context a CheckboxedTable is a table where the first column is always a checkbox; but it would also allow for rendering views like a file permissions table - where you need read,write and execute checkboxes, probably presented after the label for the file name.

freakboy3742 commented 3 years ago

Following up after the discussion on #1022:

I maintain that I'd prefer to see "widget anywhere in the table" be the supported API for Toga's Table, and CheckboxedTable is a workaround I'd rather avoid.

However - I would be willing to entertain a short-term fix, in the sprit of "do the best we can until we can work out the long-term fix".

If Winforms Table has a straightforward API to allow the first column to have a checkbox, but nothing else - then let's provide that. If the user specifies the first column as having a checkbox widget, use the Winforms API that enables that feature. If they specify a widget anywhere else, or a first-column widget other than a checkbox, raise a warning indicating it's not implemented.

This allows at least some uses (in particular, the one that you've described in #1022), while leaving the door open for a "full" fix later. I'd be deeply surprised if "widget anywhere" wasn't possible - it's only a question of how much effort is involved. A partial implementation gives at least some of the desired behavior. It also exploits the key benefit of the Toga API abstraction - that we can define a public API that exposes an interface that is almost completely independent of the private implementation; and, if necessary, the private implementation can change over time without affecting user code.

saroad2 commented 3 years ago

As mentioned here, currently ListView (which toga.Table rely on) supports only text as an input to the table. It supports some additional stuff such as a checkboxes column, but not much more. The only ways I can see to bypass that is one of 2 things:

  1. Implement our own sort of "ListView" that supports addition of any widget to the view.
  2. Use a third party library that already does that. A quick search I did revealed this and this, and some others.

In both of those cases, we would need to rewrite toga.Table from scratch in Windows.

What do you think is the right way to go?

freakboy3742 commented 3 years ago

Using a third party library isn't an option IMHO, because it introduces a binary dependency; so we're going to need to build a pure-Python ListView of our own.

We've done this with DetailedList on both GTK and Cocoa; on those platforms, there isn't a "simple" drop in DetailedList widget - we've had to construct one from primitives.

You may be able to use existing implementations as a source of inspiration, and do a "code translation". If you can find a good example written in C# that has the features we need, you may be able to do an idiomatic translation to Python and get the features we need.

However, if you do use someone else's code for inspiration, be very careful about licensing. The second example from your search results looks great - and looks like it could be the start of an implementation of icons on TreeViews and DetailedListView (both of which have been long standing wishlist items for the winforms backend). However, it's also GPL3, which means it is license toxic from the perspective of Toga. We cannot use any GPL code - even as a source of inspiration - without putting Toga's codebase into legally difficult waters.

So - if you find a project that is a good candidate for a code translation, make sure it's got a license that allows liberal use, before you look at the source code. MIT or BSD would be ideal; Apache is OK; LGPL might be ok (although I'd generally prefer to avoid it - even LGPL has some explosive potential in rewrite situations); but GPL and AGPL are complete non-starters. If you look at the code and then discover it's GPL, you could find that we're in a "fruit of the poisoned tree" situation.