Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Classlib: GUI: Support "has-a" GUI objects by calling asView within Layouts #2188

Merged

Conversation

jamshark70
Copy link
Contributor

Currently, it is needlessly difficult to use subclasses of SCViewHolder in Qt layouts.

Qt layouts expect all of the member views to be Qt-native objects. However, "has-a" (rather than "is-a") is a standard way to extend the behavior of an object and there is no compelling reason why Qt layouts should rule this out.

This PR adds .asView to the items added into a layout. Normal Qt GUI objects simply return themselves. An SCViewHolder returns the view that is being wrapped. (I also had to add an asView method to the abstract Layout class, as layouts may be used within other layouts.)

Example: See https://github.com/jamshark70/ddwGUIEnhancements/blob/master/LayoutValueSlider.sc

w = Window("test", Rect(800, 200, 400, 50)).front;
w.view.layout = VLayout(
    HLayout(
        StaticText().maxWidth_(80).string_("label:"),
        LayoutValueSlider()
    )
);

Without the PR, you have to do LayoutValueSlider().asView by hand, which is a bit silly.

@crucialfelix crucialfelix added comp: Qt GUI sclang Qt components -- for IDE tickets, use "env: SCIDE" instead comp: class library SC class library labels Jun 15, 2016
@crucialfelix
Copy link
Member

This would also mean that any ObjectGui subclass can also be placed directly in layouts.

@crucialfelix crucialfelix added this to the 3.8 milestone Jun 19, 2016
@crucialfelix crucialfelix merged commit efb8c9e into supercollider:master Jun 19, 2016
@scztt
Copy link
Contributor

scztt commented Jul 11, 2016

This breaks usage of nil and numbers to create constant size or flexible spacing between elements. I believe this would be better off as something like:

if (in.respondsTo(\asView)) { in = in.asView };
out[0] = in;

@jamshark70
Copy link
Contributor Author

Oh crikey, you're right. I guess, to do it properly, we need an interface for things that can belong to a layout, perhaps asLayoutMember?

@scztt
Copy link
Contributor

scztt commented Jul 11, 2016

Nah, it seems overboard to add another "as****" method to support one narrow case. Seems like the logic is just fine being "if we can turn it into a view, then do so, else pass it along".

@telephon
Copy link
Member

telephon commented Jul 11, 2016

If the layout should support numbers, too, then we also need SimpleNumber { asView { ^this } }. The question is if there is any systematic idea about how QT goes about interpreting different types.

@scztt
Copy link
Contributor

scztt commented Jul 13, 2016

It's hard coded into our implementation of the layout classes: https://github.com/supercollider/supercollider/blob/master/QtCollider/layouts/layouts.hpp#L74

I don't really love having that kind of generic typing pushed down to the C++ level, as it's much better done in sclang-lang - but there's not much to be gained by fiddling with it.

However: I definitely don't think we can do SimpleNumber { asView {} } - the .asSomething pattern is used more or less exclusively to return Something's. It's a very weird exception to have one trivial case where asView returns something that isn't a View.

I suppose the MOST clear way to express this in the Layout code would be something that made explicit the types that were expected, and allowed a chance for trivial .asSomething conversions for each. Something like:

if (not(in.isKindOf(View) || in.isKindOf(Number) || in.isKindOf(Layout))) {
   case 
   { in.respondsTo(\asView) } { in = in.asView }
   { in.respondsTo(\asLayout) } { in = in.asLayout }
   { in.respondsTo(\asNumber) } { in = in.asNumber }
   { // unknown type -- this is an error }
}

It's a bit pedantic, but it seems like it's the most correct.....

@telephon
Copy link
Member

telephon commented Jul 14, 2016

It's a very weird exception to have one trivial case where asView returns something that isn't a View.

I would tend to see this as an indication of the message asView being not correctly named. Alternatively, the specific implied types in the array that is used to specify those values within a GridLayout needs to check for different indices differently.

@telephon
Copy link
Member

telephon commented Jul 14, 2016

@scztt re your "pedantic" variant: it looks like there should be a better and more idiomatic OOP solution. Testing for those properties is a bit upside down. You'd rather implement a message in each of those classes that returns the appropriate thing.

e.g. asLayoutElement, returning this.asView etc. dependent on the receiver.

@jamshark70
Copy link
Contributor Author

I quote:

jamshark70
commented 4 days ago
Oh crikey, you're right. I guess, to do it properly, we need an interface for things that can belong to a layout, perhaps asLayoutMember?

@scztt
Copy link
Contributor

scztt commented Jul 15, 2016

@jamshark70
I think I agree now. :) I'm doing too much C++ programming lately, and was thinking of .asSomething as more or less a typecasting operation. But as I think about it, it's used for more flexible kinds of argument conversion all the time (as. That's much better than the type checking thing. So, is the right thing something like this?

+Number { asLayoutElement { ^this }}
+Layout { asLayoutElement { ^this }}
+View { asLayoutElement { ^this }}
+Object { asLayoutElement { ^this.asView }}

(The last only because making non-View subclasses respond to asView is a common use case)

@telephon
Copy link
Member

maybe add

+Array { asLayoutElement { ^this.collect { |x| x.asLayoutElement } }

If that makes sense.

@jamshark70
Copy link
Contributor Author

+Array { asLayoutElement { ^this.collect { |x| x.asLayoutElement } }

It's required: arrays are used to attach stretch factors and alignment to views, according to http://doc.sccode.org/Classes/LineLayout.html#*new

Oh, that means we'll need Symbol as well.

And, Array or SequenceableCollection?

@telephon
Copy link
Member

best is SequenceableCollection.

General rule, perhaps:

  • Array / ArrayedCollection: either where we really want to restrict, or where primitives are in place
  • SequenceableCollection: anything that supposes an order and isn't limited to some other specific collection class
  • Collection: anything that supposes no order and isn't limited to some other specific collection class

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp: class library SC class library comp: Qt GUI sclang Qt components -- for IDE tickets, use "env: SCIDE" instead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants