Community
Participate
Working Groups
The e4 CSS support requires an ability for widgets to notify the CSS engine that style information can be applied. This notification should occur at the end of the widget creation cycle, conceptually just before the execution stack is popped and control is returned to the application code instantiating the widget. The result of the notification would be that the CSS engine could apply style information in the form of calls to existing widget API (e.g. setting fonts and colors). In discussions with SN, it wasn't clear how this could be done without requiring extra work on the part of extended widgets. Since there is currently no "widget is finished creation" phase notification, it seems that each widget must explicitly at the end of it's constructor call some new API like notifyWidgetCreated(). Thus extended widgets must modify their constructors to do this; they cannot get it for free AFAIK. A second issue is double or premature notification due to subclassing. For example, the Nebula Gallery is a subclass of Canvas. But Canvas is itself a concrete widget useable on its own. At the end of the Canvas() init method, there would need to be a call to notifyWidgetCreated(). But at the end of the Gallery widget, there must also be a notifyWidgetCreated(), since only at that point will the Gallery internal state be initialized such that it's setters can be called legally. This could result in double notification, with both Canvas and Gallery notifying the same listener. Worse, if both notifications looked like they were wrt the Gallery widget, the first one (from Canvas' call to notifyWidgetCreated()) could cause the receiver to prematurely attempt to make Gallery setter calls prior to the subclass being initialized.
We would have do to something like: if (getClass().getName().equals("org.eclipse.swt.Canvas")) { ... do the work ... } I don't think there is any good answer to this problem, other than inventing a widget creation cycle and invalidating all the existing code. I forget all the details of this discussion but we can have them all again, here, when Silenio gets back.
(In reply to comment #1) > We would have do to something like: > > if (getClass().getName().equals("org.eclipse.swt.Canvas")) { > ... do the work ... > } Yeah, a bit ickky though. Or does this work? Introduce: Widget(Widget parent, int style, boolean notifyOfCreate) with Widget(Widget parent, int style) { this(parent, style, true); } and Canvas(Widget parent, int style, boolean notifyOfCreate) { super(parent, style, false); ... if(notifyOfCreate) { ... }; } Gallery(Widget parent, int style, boolean notifyOfCreate) { super(parent, style, false); ... if(notifyOfCreate) { ... }; } > I forget all the details of this discussion but we can have them all again, > here, when Silenio gets back. I tried to capture it as best I could in this bug but yeah we can discuss with Silenio on his return. I believe our inescapable conclusion was that there was no free lunch for extended widgets. But my comment was that there wasn't one anyway, since in order to style the extended widget specific attributes, you needed to write CSS extension code anyway to convert the css property change into a call on the widget subclass. When writing that code, you should get together with the widget owner to ensure it notifies correctly.
What if the client want to immediately change the widget's style after it is created? Would the style information be applied twice in that case? It seems like you may want to tie-in style application to layout, since it is another thing you want to only happen one time. Sort of like commitProperties() in Flex. Also, wouldn't you want this method to be like an "addNotify()". It would have to be called after construction, but also if you reparented the widget, right?
(In reply to comment #3) > What if the client want to immediately change the widget's style after it is > created? Would the style information be applied twice in that case? The goal with CSS is that you don't change the widget's style (well, not directly from the caller who is instantiating the widgets). You can however do things like change it's ID and CSS Class, and doing so would trigger a second styling pass. So now that you mention it, one would like to be able to set these from within the constructor to avoid double styling, which currently isn't possible. Related therefore is bug #260407. > It seems like you may want to tie-in style application to layout, since it is > another thing you want to only happen one time. Sort of like commitProperties() > in Flex. I don't know Flex, who calls commitProperties()? I should preface with the fact that we would like callers to be able to avoid doing anything extra/special to get the CSS styling triggered. This provides backwards compatibility and allows good separation between widget construction and styling. So although one can explicitly call the styling engine today post widget creation, we'd like the programming model to be such that you'd almost never do that. That said, you're correct that conceptually styling and layout go together. Presently we've not committed to CSS layout, just styling, because the workbench does so much dynamic layout that it's not clear how to mix the two. But we'll likely end up with some kind of declarative layout for say spacing around the widgets. > Also, wouldn't you want this method to be like an "addNotify()". It would have > to be called after construction, but also if you reparented the widget, right? Yes good, that's a requirement I forgot to mention: restyling must happen if parenting changes because style rules can be parent chain specific.
(In reply to comment #4) > (In reply to comment #3) > > What if the client want to immediately change the widget's style after it is > > created? Would the style information be applied twice in that case? > > The goal with CSS is that you don't change the widget's style To clarify, I mean you don't directly call widget API for changing colors, fonts, etc. You rely on the declarative style sheet for that.
> I don't know Flex, who calls commitProperties()? > > I should preface with the fact that we would like callers to be able to avoid > doing anything extra/special to get the CSS styling triggered. Yes, commitProperties in Flex is "scheduled" and called magically at the right time before stuff would repaint. If not, let's say that's true ;-). Similarly, in SWT, I can do: button.setPressed(true); button.setBackground(RED); And the "system" is smart enough to queue and later paint the button just once, without any explicit requests from the client. Unfortunately, things are not as easy when I do this: button.setText("Foo"); button.setFont(ARIAL); A repaint will happen, but layout is left to the caller, and it's not easy. In practice, the caller has no idea how far up the parent chain to go to request a layout. It would be nice if CSS and even layouts were more "automagic". Another scenario is you change the style "class" for both a composite and a child control. Both changes affect the Font for the child, so you'd only want to refresh it once. The mark-dirty-and-schedule-update pattern for painting would be ideal for this new style application as well as improving the existing layout support. I know it's not built-in to the platforms like (re)painting, but there are ways to achieve the same.
Should we revive this discussion again? Would it be possible to add every newly created widget (from the constructor of Widget) to a set, without notifying eagerly at that point, and then at the next convenient time before the next repaint - equivalent of timerExec(0) - the notification is sent for all objects in that set?
(In reply to comment #7) > Should we revive this discussion again? From my point of view this is a *must have* for e4 1.0/Eclipse 4.0.
John A had an interesting take on the 'batching' pattern. In the current Jobs framework you can have a single job that owns the list and adding to the list calls the 'schedule' method (which is a no-op if it's already been scheduled). One of its interesting aspects is that you can call 'schedule' even if the job is currently running and it'll simply add itself back to the tail of the scheduling list once it's done. We might have to make the list.add method thread safe so that if the job is currently running the first 'add' blocks until it's finished (then it proceeds, calls 'schedule' again...). Under most scenarios it'd be likely that all the necessary adds would take place before the job actually starts.
(In reply to comment #8) > (In reply to comment #7) > > Should we revive this discussion again? > > From my point of view this is a *must have* for e4 1.0/Eclipse 4.0. > Agreed. And to be clear, this effectively implies that it needs to happen by Sept. of this year.
> A repaint will happen, but layout is left to the caller, and it's not easy. > In practice, the caller has no idea how far up the parent chain to go > to request a layout. It would be nice if CSS and even layouts were > more "automagic". I couldn't agree more. FYI, this is the problem described by bug 103863. In fact, in order for this support to be used in the way it was intended, you'd pretty much need to fix bug 103863 too. If you have an automatic listener that's changing widget fonts and whatnot when a widget is reparented based on the parent's CSS data, that would have consequences for the widget's preferred size... so you'd need a way to mark the widget as requiring a layout before the next repaint without actually knowing the details of all the parent layouts. FYI, bug 103863 had working code for mark-and-sweep SWT layouts attached (although it's probably somewhat stale by now).
(In reply to comment #10) > (In reply to comment #8) > > (In reply to comment #7) > > > Should we revive this discussion again? > > > > From my point of view this is a *must have* for e4 1.0/Eclipse 4.0. > > > Agreed. And to be clear, this effectively implies that it needs to happen by > Sept. of this year. We're half way through September, by the way. :o
This looks more like a discussion bug to me.
The associated commit http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=f15ff0bb3cff4bd3ecbcf7fe360d6cd226272c84 added magic to Widget#setData(String, Object), but only explained this in the Javadoc of Widget#reskin(int). The added magic looks unused, but since it's API, we can't just remove it. Fixed the Javadocs with http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=3aeecc6050b5ad0d4a59c4b4f7650726018a0db3