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

Maximize button for resizable instruments #7514

Conversation

michaelgregorius
Copy link
Contributor

@michaelgregorius michaelgregorius commented Sep 20, 2024

Show the maximize button for resizable instruments.

Most other changes have the character of refactorings and code reorganizations.

Remove the negation in the if condition for resizable instruments to make the code better readable.

Only manipulate the system menu if the instrument is not resizable.

Add a TODO to the special code that sets a size.

Unfortunately there are still some artifacts for some reason, i.e. the title bar still seems to be shown for a maximized instrument window:

7512-ArtifactsForMaximizedInstrumentWindow

Show the maximize button for resizable instruments.

Most other changes have the character of refactorings and code
reorganizations.

Remove the negation in the if condition for resizable instruments to
make the code better readable.

Only manipulate the system menu if the instrument is not resizable.

Add a TODO to the special code that sets a size.
@michaelgregorius michaelgregorius linked an issue Sep 20, 2024 that may be closed by this pull request
1 task
@michaelgregorius
Copy link
Contributor Author

Ok, this one is weird. I have added the following code snippet to MainWindow::finalize right after the for loop that adds the editor windows:

auto wid = new QWidget();
wid->setMinimumSize(QSize(200, 100));
wid->setWindowTitle("Window title");
//wid->setStyleSheet("background-color:#108010;");
addWindowedWidget(wid);

As you can see setting the style sheet is commented out and can be commented back in. Here's how the maximized window looks without a style sheet being set:

7512-WithoutStyleSheet

The title bar of the window can still be seen for some reason.

Here's the same situation but with the style sheet being set for the new window/widget:

7512-WithStyleSheet

Now there is no title bar and it looks like expected.

I guess the instrument window is in some strange in between state.

Does anybody have an idea what causes this behavior?

@michaelgregorius
Copy link
Contributor Author

This seems to be caused by LMMS' own SubWindow class because it works as expected if I directly add a QMdiSubWindow via the MDI area:

auto wid = new QWidget();
wid->setMinimumSize(QSize(200, 100));
wid->setWindowTitle("Window title");
m_workspace->addSubWindow(wid);

@michaelgregorius
Copy link
Contributor Author

Maximizing also works as expected when the instrument window is added as a "normal" QMdiSubWindow, i.e. not as a SubWindow:

7512-InstrumentsWithQMdiSubWindows

In `SubWindow::paintEvent` don't paint anything if the sub window is
maximized . Otherwise some gradients are visible behind the maximized
child content.

In `SubWindow::adjustTitleBar` hide the title label and the buttons if the
sub window is maximized. Always show the title and close button if not
maximized. This is needed to reset the state correctly after
maximization.
Add the helper method `SubWindow::addTitleButton` to reduce code
repetition in the constructor.
Disable the minimize button by taking the current flags and removing
the minimize button hint from them instead of giving a list which might
become incomplete in the future. So only do what we want to do.
Remove a dependency on the `MdiArea` when checking if the sub window is
the active one. Query its own window state to find out if it is active.
@michaelgregorius
Copy link
Contributor Author

This PR is now ready for review as I have managed to fix the problems with the SubWindow class so that it now looks like in the screenshot above:

7512-InstrumentsWithQMdiSubWindows

I have also added some other small improvements to the SubWindow class.

Fix a typo and add a newline to the end of the file.
@sakertooth
Copy link
Contributor

@michaelgregorius, I have plans to revert a good chunk of #7453, which would affect this PR. I don't think we should keep moving forward with making SlicerT bigger/resizable for now until we properly rework the instrument window to support larger sizes the right way. Effect racks and (at the very least) Lv2 layouts do not render properly and the envelope tab is massively distorted.

We will always have another chance at making the instrument windows bigger, it's not like I am throwing that idea out completely. I just don't think its worth progressing further with this knowing the massive regressions we still have to deal with (and I do not like how resizability/bigger sizes for instruments was implemented).

@michaelgregorius
Copy link
Contributor Author

@sakertooth, this pull request can be reviewed and merged nevertheless. The changes in src/gui/instrument/InstrumentTrackWindow.cpp prepare the instrument window to do "the right thing" once it is resizable and the changes in SubWindow fix a problem that exists in the class independent of instrument resizing.

So, I'd appreciate a review.

@JohannesLorenz
Copy link
Contributor

This PR will conflict with #7524 . I would like to ask for time to consolidate the differences and commonalities to avoid merge conflicts and unncessary commits.

@JohannesLorenz
Copy link
Contributor

JohannesLorenz commented Oct 1, 2024

As my PR from #7524 does not fully work after the SlicerT update and conflict with your PR, I will try to use your PR for Lv2 and then see what I need to change. Wish me luck 😄

@michaelgregorius As for your PR, isn't this two separate things in one PR? Do you think it would make sense to split this PR into "add maximize button" and "fix resizing behavior"?

@michaelgregorius
Copy link
Contributor Author

As my PR from #7524 does not fully work after the SlicerT update and conflict with your PR, I will try to use your PR for Lv2 and then see what I need to change. Wish me luck 😄

Good luck then! 😅

@michaelgregorius As for your PR, isn't this two separate things in one PR? Do you think it would make sense to split this PR into "add maximize button" and "fix resizing behavior"?

Yes, it can definitively be separated as you have described. Therefore I have now separated the sub window fixes into pull request #7530. Do you want to review it?

@JohannesLorenz
Copy link
Contributor

Do you want to review it?

Yes, thanks, I added myself to the reviewer list.

I'm already in the middle of testing, most things look good.

@JohannesLorenz
Copy link
Contributor

Issue during testing:

  • New project
  • Create SlicerT (don't maximize)
  • Drag TripleOsc right into the SlicerT window

Problems:

  • TripleOsc has wrong size => Not fault of this PR
  • TripleOsc has maximize button => Should IMO be fixed in this PR

Variations:

  • Swap around TripleOsc and SlicerT
  • Ignore the "(don't maximize)"

=> In all cases, the maximize button should be updated to the new instrument
=> A maximized window should, after the instrument changes, only be maximized if the new instrument supports it

Copy link
Contributor

@JohannesLorenz JohannesLorenz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I did:

  • First functional review
  • Testing review

What needs to be done:

  • Style review
  • Second functional review (IMO optional)

src/gui/instrument/InstrumentTrackWindow.cpp Outdated Show resolved Hide resolved

if (m_instrumentView->isResizable())
{
// TODO As of writing SlicerT is the only resizable instrument. Is this code specific to SlicerT?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that the diff between InstrumentView (which contains SlicerT OR ZynAddSubFx OR TripleOsc etc) and the whole subwindow is just not dependent on the instrument (SlicerT), but it is rather:

  • The additional width is the small border left and right of SlicerT to form the whole SubWindow
  • The larger 208 height is for the PianoRoll below and the knobs etc above?

It might be interesting (but also terrifying) to check if the calculation matches the numbers from PianoView, InstrumentTrackWindow etc. 😆

Clear the `Qt::MSWindowsFixedSizeDialogHint` flag for resizable
instruments (symmetric to the `else` case).
Update the title bar of an instrument's sub window if the model changes, e.g. if an instrument is exchanged via drag & drop.

The main fix is to call the new method `updateSubWindowState` in `InstrumentTrackWindow::modelChanged`. It contains mostly the code that was previously executed in the constructor of `InstrumentTrackWindow`. The constructor now simply calls this method after it has put the constructed instance into a sub window.

With the current implementation the sub window needs to be explicitly triggered to update its title bar once the flags have been adjusted in `updateSubWindowState`. This is done with the new public method `SubWindow::updateTitleBar`. Please note that such an explicit update is not needed if the instrument windows are managed by a `QMdiSubWindow` instead of a `SubWindow`. This means that the implementation of `SubWindow` is still missing something that `QMdiSubWindow` does. However, debugging also showed that setting the window flags of the sub window does not seem to lead to an event that could be caught in `SubWindow::changeEvent`. This was found out by simply dumping the event types of all events that arrive in that method and exchanging an instrument.

The method `updateSubWindowState` uses the added method `findSubWindowInParents` to find the sub window it is contained in. The latter method should be considered to be moved into a templated helper class because it might be useful in other contexts as well.

## Technical details

If you want to experiment with using QMdiSubWindows then simply add the following method to `MainWindow` (right next to `addWindowedWidget`):
```
QMdiSubWindow* MainWindow::addQMdiSubWindow(QWidget *w, Qt::WindowFlags windowFlags)
{
	// wrap the widget in our own *custom* window that patches some errors in QMdiSubWindow
	auto win = new QMdiSubWindow(m_workspace->viewport(), windowFlags);
	win->setAttribute(Qt::WA_DeleteOnClose);
	win->setWidget(w);

	m_workspace->addSubWindow(win);
	return win;
}
```

Then call that method instead of `addWindowedWidget` in the constructor of `InstrumentTrackWindow`:
```
QMdiSubWindow* subWin = getGUI()->mainWindow()->addQMdiSubWindow( this );
```

You can then comment out the cast and the call of `updateTitleBar` in `updateSubWindowState` and everything will still work.
Show or hide the "Size" and "Maximize" entries in the system menu
depending on whether the instrument view is resizable or not.
Show the sub windows of non-resizable instruments as normal if the sub
window is maximized because it was previously used with a resizable
instrument.
@michaelgregorius
Copy link
Contributor Author

Issue during testing:

* New project

* Create SlicerT (don't maximize)

* Drag TripleOsc right into the SlicerT window

Problems:

* TripleOsc has wrong size => Not fault of this PR

* TripleOsc has maximize button => Should IMO be fixed in this PR

Variations:

* Swap around TripleOsc and SlicerT

* Ignore the "(don't maximize)"

=> In all cases, the maximize button should be updated to the new instrument => A maximized window should, after the instrument changes, only be maximized if the new instrument supports it

@JohannesLorenz, all issues except for the "TripleOsc has wrong size => Not fault of this PR" should be fixed by the last three commits.

…onForResizableInstruments

Conflicts:
* include/SubWindow.h
* src/gui/SubWindow.cpp
Copy link
Contributor

@JohannesLorenz JohannesLorenz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I did:

  • First functional review

What needs to be done:

  • Testing review (I volunteer for it once the code is final)
  • Style review

while (p != nullptr)
{
auto mdiSubWindow = dynamic_cast<QMdiSubWindow*>(p);
if (mdiSubWindow)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 2 are other good candidates for "inlining".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is only a style issue which is a matter of taste I'd rather keep it as is. I find it more readable and due to the braces it is also not very prone to "Heartbleed-like" issues if code is added.


if (instrumentViewResizable)
{
// TODO As of writing SlicerT is the only resizable instrument. Is this code specific to SlicerT?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this is still not fixed - see my previous comment.

src/gui/instrument/InstrumentTrackWindow.cpp Show resolved Hide resolved
src/gui/instrument/InstrumentTrackWindow.cpp Outdated Show resolved Hide resolved
src/gui/instrument/InstrumentTrackWindow.cpp Outdated Show resolved Hide resolved
src/gui/instrument/InstrumentTrackWindow.cpp Outdated Show resolved Hide resolved
Rename `updateSubWindowState` to `updateSubWindow`.
@michaelgregorius
Copy link
Contributor Author

What I find strange about this method: It is no way specific to Instrument Track SubWindows (except the "isResizable" which I plan to generalize to both Instruments and Effects, i.e. to PluginView, but not all SubWindow types - nonetheless, SubWindow might just do a qobject_cast on its children, and if it's a PluginView, use the isResizable from there).

I guess your PR is only required for instruments, because they are the only SubWindow type that can be maximized and can both be resizable or not? In this case, the issue will occur for Effects sooner or later. And for the other SubWindow types, I assume it might not harm?

The advantage of putting that code into SubWindow would be cleaner encapsulation and no need to find the parent.

Moving this discussion out of the code thread, @JohannesLorenz.

Yes, it should definitively be generalized.

However, with the current hierarchy this would not really work well (I think you already mentioned some of the problems somewhere else). With regards to the instruments the PluginView only describes the instrument specific widget, e.g. the orange 3OSC window, via InstrumentView which inherits from PluginView. However, the child of the SubWindow is the InstrumentTrackWindow which described the full window with all tabs, etc. and which has rather unspecific inheritances (QWidget, ModelView and SerializingObjectHook).

So it seems that some more specific class would have to be inserted that InstrumentTrackWindow and whatever class deals with the effects can inherit from. Let's call it PluginMainView for now. It might even be that the isResizable method would then need to be moved into PluginMainView so that the sub window can query it (assuming that PluginMainView is the direct child of the sub window).

Regarding moving logic into the sub window. In that case I'd prefer a sub window class like PluginSubWindow which would inherit from SubWindow and receive a PluginMainView into its constructor and which would then operate on this instance. That way SubWindow would only deal with the technical aspects, e.g. how to render itself, whereas PluginSubWindow would be used for functional or "business" aspects.

I am still not sure why SubWindow exists though? What problems is it expected to solve? I am asking because due to its imperfect implementation it is also causing lots of problems. See for example the public method updateTitleBar which had to be introduced because it does not update automatically whereas a QMdiSubWindow does.

@JohannesLorenz
Copy link
Contributor

JohannesLorenz commented Oct 11, 2024

I am still not sure why SubWindow exists though? What problems is it expected to solve?

Only to that specific question: Did you see the comment in the header (above the class) and especially in the cpp above SubWindow::moveEvent?

See commit 7cc917c . The author @Wallacoloo might want to say something about it, too.

@Wallacoloo
Copy link
Member

Wallacoloo commented Oct 11, 2024 via email

@Wallacoloo
Copy link
Member

Wallacoloo commented Oct 11, 2024 via email

@michaelgregorius
Copy link
Contributor Author

Thanks for the heads up, @Wallacoloo! I could not reproduce any of the problems while changing the state of the sub windows and the main window (under X11). However, I guess switching to QMdiSubWindow now would likely open another can of worms anyway as it does not seem to support style sheets very well.

@JohannesLorenz
Copy link
Contributor

JohannesLorenz commented Oct 12, 2024

Regarding the rest of the Subwindow generalization discussion: This is all a bit complex, and might change drastically as soon as I change the hierarchy of PluginView/EffectControlDialog/EffectView. So I suggest either waiting until I have a PR here, or finish this PR as it is (open comment to solve, outstand test review). Ultimately, the decision is up to the author - I would accept both.

@michaelgregorius
Copy link
Contributor Author

Regarding the rest of the Subwindow generalization discussion: This is all a bit complex, and might change drastically as soon as I change the hierarchy of PluginView/EffectControlDialog/EffectView. So I suggest either waiting until I have a PR here, or finish this PR as it is (open comment to solve, outstand test review). Ultimately, the decision is up to the author - I would accept both.

I'd say lets first do the hierarchy changes, hoping that they might make it easier or clearer how to solve the remaining problems with this PR.

@JohannesLorenz
Copy link
Contributor

lets first do the hierarchy changes

I uploaded them into a PR now: #7544 .

@JohannesLorenz
Copy link
Contributor

IMO the comment from @SpomJ can be ignored, as this would, if even, be handled in #7524 (see my comment to their comment). We are also a bit under time pressure (sorry, partially my fault), because this PR could influence #7201 .

Regarding the rest of the Subwindow generalization discussion: This is all a bit complex, and might change drastically as soon as I change the hierarchy of PluginView/EffectControlDialog/EffectView. So I suggest either waiting until I have a PR here, or finish this PR as it is (open comment to solve, outstand test review). Ultimately, the decision is up to the author - I would accept both.

I'd say lets first do the hierarchy changes, hoping that they might make it easier or clearer how to solve the remaining problems with this PR.

@michaelgregorius We were stopping here with the review: #7514 (comment) . Since my hiearchy changes are not going to be realized we should continue there: There are still open comments from the previous review, and then the PR must be tested. Does that make sense?

@michaelgregorius
Copy link
Contributor Author

@JohannesLorenz, I have merged the current master and did a quick test. Maximization is still working. Is there anything else to do?

@michaelgregorius
Copy link
Contributor Author

As noted before this PR fixes some general problems with maximizing Instrument windows correctly. IMO we can merge it and if the maximization feature is not wanted then it would suffice to only remove the code that does something with the Qt::WindowMaximizeButtonHint flag so that the feature can be added back quickly and in a working state if it is wanted.

Copy link
Contributor

@JohannesLorenz JohannesLorenz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be merged

@michaelgregorius michaelgregorius merged commit 303215f into LMMS:master Jan 1, 2025
9 checks passed
@michaelgregorius michaelgregorius deleted the 7512-MaximizeButtonForResizableInstruments branch January 1, 2025 13:26
@JohannesLorenz
Copy link
Contributor

@michaelgregorius Sorry, abusing this PR for contacting you. I am just going through the conditions to resizability of InstrumentViews (mainly for #7524), and I wonder if our idea to introduce a virtual isResizable(...) is good. Shouldn't we just use the existing way of letting all InstrumentView child classes calling setSizePolicy(...) instead of constructing a bypassing, redundant system to transfer this information to the parents?

Btw, I remember you once wrote how I can contact you? Sorry, I do not find the info anymore. If you want to discuss, maybe an instant messenger might be better than reviving an old PR 😆 Though I don't have a strong opinion here, either.

@michaelgregorius
Copy link
Contributor Author

@JohannesLorenz, if this does not break anything else then it might also be worth a try. I guess this would mean that the method isResizable would be removed from EffectControlDialog, PluginView and all inheriting classes. Both base classes would then call something like setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) in their constructors.

Every class that now overrides isResizable by returning true would then need to call setSizePolicy with some other policies than Fixed. And the test if a widget is resizable would turn into checking the respective size policy.

The code in EffectView might perhaps be changed to simply pass on the size policy of the child to the sub window.

Only thing I am not sure about is in how far the size policy of a widget is specific to layout contexts or if it is a general property. However, I guess it is also evaluated if a widget is for example a top-level widget that's not inside a layout. So it might be general anyway.

I think I proposed to discuss things in Jitsi Meet because I assumed a "real" meeting. However, I cannot find that issue/comment anymore, either. 😅 Alternatively you can always ping me here in the relevant issues.

@JohannesLorenz
Copy link
Contributor

@michaelgregorius I have just read a lof of Qt stuff. Finally, (I think) I found out: While QWdiget::setFixedSize decides whether the widget can resize after creation, QWidget::setSizePolicy decides how the widget behaves in case of a resize, which can happen both at widget initialization or user resize.

However, I guess it is also evaluated if a widget is for example a top-level widget that's not inside a layout. So it might be general anyway.

When I tried to set the sizePolicy of a QMdiSubWindow to Fixed, it was still resizable. From what I read, I would even conclude that QWidget::setSizePolicy is irrelevant for a QMdiSubWindow, because it is a toplevel widget...

Every class that now overrides isResizable by returning true would then need to call setSizePolicy with some other policies than Fixed. And the test if a widget is resizable would turn into checking the respective size policy.

All in all, I guess I will rather use QWdiget::setFixedSize in #7524.

The code in EffectView might perhaps be changed to simply pass on the size policy of the child to the sub window.

I just found out that this seems to work great in InstrumentTrackWindow (more or less the analog case).

@michaelgregorius
Copy link
Contributor Author

@JohannesLorenz, Qt's use of sizes and sizing is definitively a complex topic so it's easy to get lost in there for hours. 😅

I think setFixedSize means that a widget gets a fixed size and is always rendered at that size regardless of its content, be it what it paints itself or with regards to its child widgets with their own sizes and policies. A fixed size widget will always have the set size regardless of whether it's a top level widget or a child in a layout.

The size policy on the other hand is mainly used by other "clients" to inquire a widget about its capabilities with regards to making use of available space and its need for space. Example for clients are layout algorithms which need to check how to distribute available space to widgets. So it is mainly something that's interesting for "others".

To me it always feels a bit like one thing is "driven" from the top whereas the other is driven from the bottom.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Maximize button in SlicerT
5 participants