s00500 / ESPUI

A simple web user interface library for ESP32 and ESP8266

Home Page:https://valencia.lbsfilm.at/midterm-presentation/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature Request: Vertical orientation for Slider / Switcher, "Group" control

codefaux opened this issue · comments

Not really a problem per se, but I'm attempting to make a UI interface similar to VoiceMeeter's new VMR-StreamerView app. I've got the back end tied up, and I'm prototyping the UI --

SIDE NOTE, fantastic library, by the way, I'm really loving it and there is literally no other option which suits my needs. Thank you so much. It's dead simple to use.

I apologize for asking so much of your attention, but please take a moment (or several) for my verbosity; I honestly feel it's worth the time of several strangers building a library for people they don't know, and I do respect and value your time.

Anyway, I'd like to see, essentially, the same Slider/Switcher controls, but turned on their side. I don't really think other controls (aside from maybe Labels but that seems tricky) could benefit from a vertical layout, so really it's just those two. My target UI is "generally accepted" to use vertical sliders, so I'd like to try for that.

Extra forever-love points for a per-control graphical style alternative similar to a progress bar for Sliders in general (or just a control, Progress, essentialy cloned from the Slider and visually restyled) and a Lit/Unlit graphical style alternative similar to a push-button panel switch for Switches in general (or, again, a cloned control) -- Maybe there is a DIY route already available for this and I just haven't figured that out, if so I apologize. Anyone know which guts to fiddle to accomplish this myself? I'm not opposed, it's just too far outside my wheelhouse.

The second (third?) request would be a Group control, to densely cluster similar controls in a line.

My implementation suggestion (the template literally asks for it, I'm sorry! I always feel imposter syndrome making suggestions for other people's projects!) would be;

  • configure the base Control class to hide its background visually if it has a Parent.
  • implement the Group control such that other controls assign it as their Parent (done?)
  • implement the Group control as an empty cell with the normal background pad used for all other controls, and a variable-geometry "container-like" element -- base element being HTML Tables (maybe trivial depending on your internal layout already?)
  • allow the Group control to manipulate the placement of its children -- IE, rendering them inside individual HTML Table cells
  • add Layout as a global control property (supporting Vertical Sliders/Switches as variants rather than separate types) with two possible values, Horizontal and Vertical, but discarded on controls which cannot render vertically. (HTML Tables' Row vs Column per-element)
  • implement the Group control's Value (as set for all other controls ie Text, Slider position, etc) to adjust intra-control spacing in the direction of its Layout (HTML Table properties)
  • add a global Control class property, Margin, which solely influences the perimeter gap between the contents of the control, and the background pad perimeter. This could allow (for example) to control the size of the background padding per-control, and when inside a Group it would still apply, but cause the control to be smaller, or the Group to be larger. This is the behavior of the Margin property in HTML and Windows Forms elements, and likely more, and is a small variable with a big effect, especially when combined with Groups.
  • Behind the scenes, all the things here can be done with an HTML table with a single row or column and basic properties, so the web-side framework exists, is predictable, and is easy to leverage. I'm not sure how easy it is to -implement- but that's why we're here.

As a consideration, restricting Groups to identical child control types would be an acceptible compromise for code/layout simplicity, especially if Groups could be nested; a group of Groups are all the same class, even if they hold different Classes. This would further be easier with my suggestion of the background pad removal being implented in the base Control class. Or we could just not care if the layout looks horrible and add controls exactly as asked; it's on the end user to sort out by making better choices? (lol.)

This implementation considers the minimum viable effort for something A) usable, B) deceptively versatile, and C) easily comprehensible/demonstrable, which represents a solid overall value improvement to even the average end user -- though vastly moreso to the "power user". I also tried to consider an approach which would be 100% backward-compatible with current user code by assigning optional arguments with sane defaults to new parameters in order to match current implementation results with no changes to end-user code, and furthermore could be completely ignored by users not wishing to use or even know about the added complexity. (IE, the only downside to implementation -- which I can see from my admittedly external view while still trying to be deeply objective -- is difficulty of implementation itself.)

For a real-world perspective of how amazing this all could arrange to be if all implemented as I humbly suggest a simple sample UI;
-Populate three groups
--Group A with Layout set Horizontal, containing Sliders with Layout set Vertical
--Group B with Layout set Horizontal, containing Switchers with Layout set to Horizontal
-Group C with Layout set Vertical, containing Groups A and B.
This simple arrangement of nested groups using only -two- configurable options (h/v layout, intra-element pad) and existing controls* would give you a very snappy looking Mixer UI which take up minimal space without compromising usability and at-a-glance comprehension. In Group A, the two sliders side-by-side could be set to a "Progress Bar"-alike graphical view could represent an audio dB meter, and the next two sliders with the normal Bubble-on-a-line graphical style could represent the Fader controls. Beneath that set of sliders, a tactically-spaced row of Switchers, representing various fancy Mixer things like Muting switches, or even extra Groups for Sends and so forth... Users could create progress bars to synchronize with their long-running actions using the new Slider graphical style (or just the cloned Progress control) etc etc etc..

Thank you for giving me your time, I apologize for taking so much and I hope it was worth it. There really aren't any alternatives to a vertical layout for my intended app, but frankly if it's not viable to implement I can just deal with that, lol, I'm just one user. The alternate graphical styles would be a bonus, but I feel they would suit other UI designs nicely, without adding much extra complication for you or your target user. The Group control is something I felt was "missing" from this library from the outset, coming from a Windows Forms design background I've made amazing use of control grouping with automatic layouts and untethered control of just spacing and margins, simply by nesting Groups. This UI toolkit really is unlike anything else out there, and these tweaks really would turn it into a powerhouse of frontend design.

Keep being awesome.

The second (third?) request would be a Group control, to densely cluster similar controls in a line.

+1. Being able to group controls would be fantastic. Or if not practical, then an alternative would be a function that starts a new row with a horizontal line to help visually group the elements. FWIW, this was mentioned in #115 (comment)

  • Thomas

As you can see from the PR above, I've implemented a pile of things talked about in this. However, codefaux, your suggestion essentially tears up the way the UI is currently done and reflows the entire thing so I didn't want to propose that because it would break many existing UIs. Also making it responsive to small screens would be impossible with tables and a bit of a nightmare with modern CSS.

Anyway, I picked a compromise that allows for some neat things without breaking anything.

I'm now looking at vertical orientations for sliders/switchers. Switchers are easy (you just rotate them in CSS), sliders...less so. It...might work..? I'll investigate.

Hey, that's fantastic, thank you. As for my suggestion directly -- I can understand it being the wrong approach, mostly because I don't have my head around how it all works nearly so well as you do.

The short end of it is, I'm glad to hear you've made this update happen, my suggestions were more conceptual than desired implementation. Your changes look fantastic and I'm really interested in jumping back in soon.

Vertical sliders would've been nice, but frankly without them I'll be just fine. I'll leave this open since you said you'd investigate, but don't consider it an obligation. If you find it's not something you can solve readily, I'm prepared to consider it closed. What you've brought to the table is more than enough.

Screenshot 2022-01-21 at 23 23 41

Turns out CSS is basically magic.

This is not merged yet, it's on one of my feature branches. If you want to mess around, pull that branch and the code that made this screenshot is:

	auto grouptab = ESPUI.addControl(Tab, "", "Grouped controls");

	ESPUI.addControl(Separator, "Vertical controls", "", None, grouptab);
	auto vertgroupswitcher = ESPUI.addControl(Switcher, "Vertical Switcher Group", "0", Dark, grouptab, generalCallback);
	ESPUI.setVertical(vertgroupswitcher);
	ESPUI.setVertical(ESPUI.addControl(Switcher, "", "0", None, vertgroupswitcher, generalCallback));
	ESPUI.setVertical(ESPUI.addControl(Switcher, "", "0", None, vertgroupswitcher, generalCallback));
	ESPUI.setVertical(ESPUI.addControl(Switcher, "", "0", None, vertgroupswitcher, generalCallback));

	auto vertgroupslider = ESPUI.addControl(Slider, "Vertical Slider Group", "15", Dark, grouptab, generalCallback);
	ESPUI.setVertical(vertgroupslider);
	ESPUI.setVertical(ESPUI.addControl(Slider, "", "25", None, vertgroupslider, generalCallback));
	ESPUI.setVertical(ESPUI.addControl(Slider, "", "35", None, vertgroupslider, generalCallback));
	ESPUI.setVertical(ESPUI.addControl(Slider, "", "45", None, vertgroupslider, generalCallback));

And you'll need to define a callback called generalCallback. Have a play!

This is fantastic! Do you have any suggestions on labeling the controls with vertical text?

BTW, the enhancements you've added are impressive. Earlier today it was a time function, now this. Can't wait to see what you come up with next. If you're looking for features to implement (a.k.a. a lot more work) then just let me know. :)

  • Thomas

I'm unsure about labelling. I've played with it for normal grouped controls and you can do it by just combining labels, inline styles, and the target controls to do things like this:
Screenshot 2022-01-22 at 10 26 29

But the code is not pretty:

	//Sliders can be grouped as well
	String clearLabelStyle = "background-color: unset; width: 100%;";
	auto groupsliders = ESPUI.addControl(Slider, "Slider Group", "10", Dark, grouptab, generalCallback);
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "A", None, groupsliders), clearLabelStyle);
	ESPUI.addControl(Slider, "", "20", None, groupsliders, generalCallback);
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "B", None, groupsliders), clearLabelStyle);
	ESPUI.addControl(Slider, "", "30", None, groupsliders, generalCallback);
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "C", None, groupsliders), clearLabelStyle);

	//We can put 4 switchers next to each other, but as they lack labels it can be hard to see
	//which is which. We can fake adding labels to them with some label controls and styling.
	auto groupswitcher = ESPUI.addControl(Switcher, "Switcher Group", "0", Dark, grouptab, generalCallback);
	ESPUI.addControl(Switcher, "", "1", Sunflower, groupswitcher, generalCallback);
	ESPUI.addControl(Switcher, "", "0", Sunflower, groupswitcher, generalCallback);
	ESPUI.addControl(Switcher, "", "1", Sunflower, groupswitcher, generalCallback);
	//This label does nothing apart from put the next 4 onto the next line
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "", None, groupswitcher), clearLabelStyle);
	//They are set to the same width as a switcher so appear below them
	String labelStyle = "width: 60px; margin-left: .3rem; margin-right: .3rem; background-color: unset;";
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "A", None, groupswitcher), labelStyle);
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "B", None, groupswitcher), labelStyle);
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "C", None, groupswitcher), labelStyle);
	ESPUI.setElementStyle(ESPUI.addControl(Label, "", "D", None, groupswitcher), labelStyle);

It's not too bad for sliders, but you can see that for switchers you need to put an invisible "line break" in and then style the labels to be the right width. Maybe there is a way to use the parentControl mechanic to attach a label to a control in a way that the receiving controls.js understands and so can implement properly...

Thanks for the examples. Very helpful.

  • Thomas

I'm closing this now as it is implemented in this pull request.

There are still improvements to be made, particularly in labelling, but they should go into new issues.