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

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

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".


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
return nullptr;
}

void InstrumentTrackWindow::updateSubWindowState()
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

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 .

subWindow->setMaximumSize(m_instrumentView->maximumSize() + extraSpace);
subWindow->setMinimumSize(m_instrumentView->minimumSize() + extraSpace);

flags &= ~Qt::MSWindowsFixedSizeDialogHint;
Copy link
Contributor

@SpomJ SpomJ Nov 20, 2024

Choose a reason for hiding this comment

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

Consider also adding setFixedSize() here. MSWindowsFixedSizeDialogHint annoyingly appears to be a windows-only thing, or at least, isn't respected on wayland, while setFixedSize() or layout->setSizeConstraint(QLayout::SetFixedSize) is.

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