Jump to content

Button with other elements over it


king2

Recommended Posts

In my project I must have buttons with other elements over, for example, labels and progressbars. My button is button that have picture and some info inside it, I must refresh some info displayed inside buttons (and I use progressbars to show audio level).

You can see screenshot here: viewtopic.php?f=28&t=243&start=80#p2485

But I have a problem, when I click to button, button itself if rising and all other elements is hiding. I need to have them displayed over button all time (more, I need to have button pressed if user was tapped over any area inside button).

Can I do this without breaking everything in uGFX? :)

Link to comment
Share on other sites

The standard uGFX window manager does not support overlapping windows as you have already seen. It does support containers but not overlapping child windows.

To implement overlapping windows is very complex and adds significant RAM and speed requirements which is why it has not been done yet.

Perhaps someone might want to take it on as a side project as the window manager is replaceable with a single API call.

There is a work-around however.

In your application when you get the event that says the button has been pressed you can manually call gwinUpdate (or is it gwinRefresh) on the slider widget that overlays the button. That will cause the slider to be redrawn.

Assuming the redrawing issues can be worked around - the only way to give your slider "pass-through" focus to the button might be to mark the slider as disabled. That should make it not interact with the mouse/touch. The style can be changed for the slider so that the disabled state looks the same as a normal enabled slider.

Whether disabling the slider is sufficient for the event to pass-through to the underlying button is untested. Normally you wouldn't want that to happen in a normal window manager but because in this case the window manager does not support overlapping windows it might just pass the event through. You would need to test that.

Link to comment
Share on other sites

  • 2 weeks later...

I have tried to disable text label placed over button. This not works :(

Button was not pressed when I clicked to text label over it.

This looks like text labels cannot generate touch events at all. As I understand, progressbars too.

How can I know in my application that user was tapped on progressbar (value changed) or tapped on text label?

Link to comment
Share on other sites

I have tried to disable text label placed over button. This not works :(

Yep, we thought that this won't work :( As mentioned this is untested as it is not the expected behavior / usage.

This looks like text labels cannot generate touch events at all. As I understand, progressbars too.

Yes, that is correct. You can see in the implementation of the label that it didn't register any functions to handle mouse interaction (line 54:56): https://bitbucket.org/Tectu/ugfx/src/a7 ... label.c-43

The same goes for the progressbar: https://bitbucket.org/Tectu/ugfx/src/a7 ... ssbar.c-38

How can I know in my application that user was tapped on progressbar (value changed) or tapped on text label?

You cant (with the default implementation of the widgets as linked above). You'd have to create your own specialized widget class for that.

As inmarket explained the best and most proper solution is to write your own window manager and register that using gwinSetWindowManager().

~ Tectu

Link to comment
Share on other sites

OK, i got it.

But why progressbars exists if I cannot get its change event? OK, tapping on text label will not used by all users (but it will be useful), but progressbar is active widget! User can change its value, but without method of obtaining change event it is just a visual element.

I do not understand...

Link to comment
Share on other sites

Note that a progressbar is just a passive element like a label. It's only purpose is to provide a visual representation of something. A progressbar shows a state of something - the user is not supposed to interact with the progressbar.

If you want a progressbar where the user can change the value then you want to use the Slider widget. In fact, the default rendering functions make them look very similar - just that the slider accepts mouse input while the progressbar doesn't take any input at all.

~ Tectu

Link to comment
Share on other sites

Thanks for pointing me to slider. They looks so similar..

But anyway, is there any chance that even passive elements will make touch events in uGFX? If yes, I can just add sending events to uGFX lib for temporary use, and use this approach in future when events will be added to main branch.

If yes, I can just react on such events.

If progressbar or text label was clicked, I can just send button's click event.

If button was clicked, I can just redraw all elements over it.

And second reason: I believe that all objects should react on clicking, this makes all widgets similar. One type (widget), one way to react (send click event when clicked). Any tap should raise event associated with some object (widget, or container, or window).

I believe this will add flexibility to library.

Link to comment
Share on other sites

In order to make the label and the progressbar widget sending events you will have to modify the actual widgets code. What you need to do is implementing the MouseDown function and register the corresponding function pointer in the widget VMT. You can find the definition of the GWIN widget VMT in /src/gwin/gwin_class.h.

However, for your particular case I would STRONGLY recommend following the advice I gave in your other thread (viewtopic.php?f=9&t=341#p2546) and implement a custom widget that does what you want for the following reasons:

  • This is the intended usage of the GWIN module
  • It is proper as it doesn't include any hacks or work-arounds
  • It's a portable and future proof solution. You can upgrade to newer uGFX versions in the future without any hassle as all your custom code is outside of the actual library.

And second reason: I believe that all objects should react on clicking, this makes all widgets similar. One type (widget), one way to react (send click event when clicked). Any tap should raise event associated with some object (widget, or container, or window).

I believe this will add flexibility to library.

Thank you for your feedback. We will consider this for future releases.

~ Tectu

Link to comment
Share on other sites

I have changed already gwin_label.c exact way you pointed in your message. It works.

Custom widget requires me to write widget with:

- progressbars or not, its positions

- text or not, positioning, font, fontsize

- changing image

- ability to react to text tapping as button click, or just as text tapping

Each time in similar situations I'm afraid that I will code not so good, or will miss something, and my code will be bad and ugly.

After all this, I will get widget that I cannot use with Studio :)

For me, fast way now - is to use event approach :(

I think that modifying core code is a bad idea, this because I'm asking about chances this changed to be a part of core code in future.

I can modify library code by myself and send patches to you, if it will be useful and will simplify including this changes into future releases.

Link to comment
Share on other sites

We agree with everything that you are saying and the most proper solution to solve your task the best way is to write that custom widget. It will not only take less time now to write that widget (as you can copy paste most of the code of existing widgets) but will also save you time when upgrading to newer uGFX versions in the future.

The only argument I can't argue with is that the uGFX-Studio currently doesn't allow you to place custom widgets. I guess that should become a more important task too. Maybe we should even provide a temporary solution for the 0.13 release - not sure.

What I can recommend you to do in the meantime (in case of you write custom widgets) is to place a dummy widget such as a console window and then just replace the code (manually by hand) once you're done. After all the studio doesn't offer much advantages besides placing the components at the moment.

I can modify library code by myself and send patches to you, if it will be useful and will simplify including this changes into future releases.

We appreciate any contributions whether they are bug reports, fixes or just patches for implementing different behavior. Things like this don't only help ourselves to improve the library over time but might also be useful for other users that face a similar problem.

~ Tectu

Link to comment
Share on other sites

but will also save you time when upgrading to newer uGFX versions in the future.

If I will make patches, and patches will be applied over uGFX, I will save my time by NOT changing code in newer versions :)

I really think it will be useful even if I will make my own widget, just to make things better (for future users).

I use text labels to display values, but I want to change value's units, for example A, mA or uA for current measurement. Best way for me - allow user to do it just by tapping on value, and.. I can't!

I will add events to uGFX passive widgets and send patches.

Link to comment
Share on other sites

If I will make patches, and patches will be applied over uGFX, I will save my time by NOT changing code in newer versions :)

That's true - as long as nothing inside the same part of the uGFX code changes that will make applying the patches fail :D

I use text labels to display values, but I want to change value's units, for example A, mA or uA for current measurement. Best way for me - allow user to do it just by tapping on value, and.. I can't!

That's a very interesting use case and we haven't thought of something like that! We'll discuss adding click events for all widgets. Thanks for your feedback!

~ Tectu

Link to comment
Share on other sites

I have forked current uGFX, cloned fork to my PC and added events to text label, progressbar and container. Event numbers - just increments from existing numbers.

I cannot make pull requests on uGFX repo (or I do not know how to do this), so I attached patch to this message.

If patch will be applied before main repo will change - all should go without problems.

I have not added events for image and graph because it is not widgets and have no widget's VMT.

patch.zip

Link to comment
Share on other sites

I strongly believe that adding event handlers for static elements is a big mistake. Static elements should be just that - static.

The real solution is recognising the correct methodology for ugfx...

If you want a progressbar with events then use a slider.

If you want a label with a click event use a button.

If it doesnt look the way you want than use a different draw routine (or a custom draw routine).

This was covered a while ago in another thread when a user was wanting a button that could retain a pressed state. The correct answer was to use a checkbox widget with a button draw routine.

Unlike other gui libraries, widgets in ugfx are defined by their functionality not by their appearance. Custom draw routines are a normal part of widget functionality used to control how a widget looks.

In this case based on the discussion Tectu's solution of creating a custom widget is probably the correct solution for your application. Patching core widget functionality is definitely not the correct approach. Adding custom draw routines is much better than your current approach but the best is to create that custom widget.

An example of a custom widget can be found in the audio recording demo. It implements a basic custom oscilloscope widget.

Existing widget code from the progress bar, buttons etc can be easily cut and paste into your own widget to create a solution that exactly matches your own criteria.

Link to comment
Share on other sites

OK, I got the point. So, my patch is useless now for me too, because it will be not applied to uGFX.

I can use button instead of text label, but can I have button without border? With auto-width? With word-wrapping? In Studio?

This means for me that I have to write my own custom draw routines and widgets for almost everything and makes Studio useless.

Thanks for clarifying your position.

Link to comment
Share on other sites

Yes you can have all you want that way however studio support is very rudimentary for the more powerful and complex ugfx features.

The reason for this is two fold...

a) studio was originally designed as a gui layout assistance tool. It was always expected that people would just use that to get an initial layout and would then manually edit the code to build their application. Over the course of the beta for studio users have made it clear they want more than that - something much more powerful than an initial layout tool. Unfortunately that extra power will be a while coming yet.

b) studio is still very much beta. There is still lots of stuff missing even for just a layout tool.

Link to comment
Share on other sites

I can use button instead of text label, but can I have button without border? With auto-width? With word-wrapping? In Studio?.

That is exactly what custom rendering functions are meant for! The widget just implements some logic - the look'n'feel can be implemented by the user of the widget however he wants.

Inside the drawing routine you can use any of the GDISP drawing functions. As Word-Wrapping is also implemented inside those GDISP functions you can easily make a button look like a label while still having word-wrapping and so on.

Note that in case of your microphone button with the two volume level indicators we'd still strongly recommend writing a custom widget for that. As mentioned before you can copy paste the corresponding parts of the rendering routine of the progressbar widget to save yourself some time.

As inmarket mentioned the uGFX-Studio is in a very early stage. It will take ages to make it become a fully featured GUI designing tool. Right now it's helpful to get started and to create quick drafts of your final GUI.

Please note that the uGFX-Studio website as well as the "New Project"-Dialog inside the studio itself clearly state that the studio is in a very early beta stage and that it is NOT meant to be used in a productive environment. Right no we don't even guarantee that project files between different studio versions are compatible.

The studio has a long way ahead of it but feedback from users like you help us to improve it quickly. We plan to release the first real version within July 2016.

~ Tectu

Link to comment
Share on other sites

I programmed on Delphi/C Builder in 90th, and it was great approach - you make display page visually, and then add reaction on events. This was pretty simple to use and to understand. Place items, write event handlers. App is ready.

All widgets (all, even label) had basic events like click, dblclick, mouseon, mouseout and similar. If you clicked on label, label's click event raises. If you missed on label and clicked on its container, container's click event was raised. If you missed on container too, window click event. One idea, one behaviour. Was no items with physical possibility to click on them, but with no click event. Each click event was detected, counted, carefully wrapped into gift pack and transferred to its receiver. Or its parent if we was missed a little.

"Widgets are defined by their functionality, not by appearance". What if I want to have text label that can be in 4 states? And it really text label, by appearance. Should I use special checkbox with extended quantity of statuses, or write special widget, or use listview with my custom draw routine, producing more and more copy-paste code just to keep idea that 'everything with more than 2 states is listbox'?

This is unusual behavior for text label, ok, but why not take label as is, with its excellent appearance (95%), and allow to programmer to add unusual behavior (5%), instead of rewriting it all by copy-paste?

What will break if static object will send events?

I think I will never understand this.. :(

uGFX allows programmer to customize many things. Plain C allow programmer to customize everything.

Sorry, I will not write such thing anymore.

Link to comment
Share on other sites

I programmed on Delphi/C Builder in 90th, and it was great approach - you make display page visually, and then add reaction on events. This was pretty simple to use and to understand. Place items, write event handlers. App is ready.

That is what the uGFX-Studio is supposed to become eventually: A tool that allows to design a complete GUI within minutes. However, the studio is a long way away from being that tool. The uGFX-Studio is currently a side project and we try to focus on working on the actual library instead. But even if we'd make the studio become our main project it would easily take a year or more to make it become a tool that is powerful enough to handle every-day GUI designing requirements.

As inmarket mentioned the uGFX-Studio was initially supposed to become nothing but a simple layout assistance tool. User feedback suggested that it should become a full GUI design suite instead and that is what our goal has become ever since. It just that we currently don't have the resources to put more time into developing the studio.

All widgets (all, even label) had basic events like click, dblclick, mouseon, mouseout and similar. If you clicked on label, label's click event raises. If you missed on label and clicked on its container, container's click event was raised. If you missed on container too, window click event. One idea, one behaviour. Was no items with physical possibility to click on them, but with no click event. Each click event was detected, counted, carefully wrapped into gift pack and transferred to its receiver. Or its parent if we was missed a little.

The µGFX library is supposed to be (as the name suggests) a very small and fast library. Whenever we write a single line of code we have to ask ourselves how we can keep both the CPU time and the memory requirements at a bare minimum. That is one of the reasons why everything is modular and why so many features (and sub-features) are completely optional. If you don't need to draw circles your compiler won't even see the circle drawing code. If your hardware provides hardware accelerated circle drawing we will take use of that and so on but everything needs to be able to run on any platform.

There are many users who use the uGFX library on a very small ultra-low power device. These microcontrollers often don't provide more than slow 16-Bit CPUs with only a couple of kilobytes of RAM and are powered by batteries way below the 100mAh mark. Every microsecond the CPU is active counts in these applications. That is why the GWIN module only implements very basic functionalities. For example it's not possible to loop through widgets in both directions as we use a singly-linked list for that. Neither is it possible to handle overlapping widgets as you have discovered. However, if you need that and if you can spare the resources you can just write a your own window manager and use it by just calling one simple function that registers your own manager. We are certain that we'll have more than just one built-in window manager in the future so that users with more complex needs will have an out-of-the box solution but we currently lack the man power to do all that and as we provide easy to use interfaces for people to do it themselves we think that things like that are a relatively low-priority task compared to other features.

Also note that after all we target embedded applications most of which are running no very low resolution displays. These types of applications usually just require a very static user interface. Unlike with a desktop computer the user usually doesn't need (or expects) to move around windows or minimize and maximize dialog boxes. That is why we spare every byte we can and hence the reason why, for example, you can't dynamically change the parent of a widget.

We will never be able to satisfy 100% of all needs but given our focus on providing highly flexible interfaces for customization wherever we can we think that we are on the right track. It's mostly just a matter of time to implement more widgets, more built-in rendering functions and more window managers to meet the needs of more uses.

"Widgets are defined by their functionality, not by appearance". What if I want to have text label that can be in 4 states? And it really text label, by appearance. Should I use special checkbox with extended quantity of statuses, or write special widget, or use listview with my custom draw routine, producing more and more copy-paste code just to keep idea that 'everything with more than 2 states is listbox'?

That is the point where you are supposed to write your own custom widget. Custom rendering routines are an easy way to quickly modify the look'n'feel of existing widgets. But when you need behavior that is not already supported by an existing widgets you have to get one step further and write your own widget. And in all cases we focus on providing a highly flexible yet very easy to use interface.

The existing facilities such as the GWIN core module, the GDISP module and so on take care of any difficult such as word-wrapping that you mentioned in a previous post. It's just a matter of calling the corresponding GDISP function that draws a string in a box using word-wrapping inside your widget drawing routine to have a widget with a text label that is automatically word-wrapper. If you need an image, just use the GDISP function that draws an image in your widget rendering function and you're done. The GWIN module will take care of coordinate translations, visibility, enable/disable state, event propagation and so on without you having to worry about anything like that.

Just create a new widget (you can copy an existing one that matches your needs the best such as the button widget), name it differently (for example "Unit Label"), modify the mouse handling functions to iterate through your four different states and implement a default rendering routine and you are done. No magic (or hacking or work-arounds) involved. And as always we are here to help if you have any questions.

What will break if static object will send events?

First of all it will have an impact on resource requirements. Even if it's just so little and totally negligible for your hardware platform it won't be for others. And secondly - and probably in this case the more important point - it will break the philosophy behind uGFX. The main goals of the uGFX library are to be very platform independent. We want to be able to run the exact same application code on a small, slow and stupid 16-bit microcontroller with a few kB of RAM and on a multi-core high performance platform with gigabytes of RAM and CPUs running in the GHz section. For that we need to do two things: 1. Everything needs to have as low resource requirements as anyhow possible and 2. everything needs to have a highly flexible and modular interface. This results in implementing something like the GWIN widget system by just focusing on the bare minimal functionalities (behavior) for each widget as inmarket mentioned. The thing that will vary from use to use is just the visual representation (the rendering function).

In uGFX you can take an existing widget and just change the rendering function or you can write your own widget. You can even write your own window manager and using it is in all three cases just a matter of one line of code. Most other embedded GUI libraries don't provide you with this freedom.

uGFX allows programmer to customize many things. Plain C allow programmer to customize everything.

See above. We are pretty confident that you won't find an embedded library that will give you more flexibility in any regard.

In any case you just should never take the uGFX-Studio into account when thinking about the actual uGFX library. We are light years away from having an uGFX-Studio that can represent the power of the actual uGFX library.

~ Tectu

Link to comment
Share on other sites

Having Studio get to the stage of something like Delphi is really what a lot of users would like and we will (eventually) get there. Delphi in my mind was one of the best development platforms that ever existed so I know exactly why you suggest that as the example. Having studio with that sort of functionality would be fantastic but is definitely a long term goal.

Having common events (such as click) across all widgets however is not feasible. A lot of people forget that this is an embedded system and its design criteria are very different to desktop style GUI's.

The issue in this case is two-fold...

  • To have every widget support a click event code would need to be added to every widget to generate that event. This seriously increases code bloat (much more than supporting custom draw routines). It can't be handled in common code for the 2nd reason below.
  • The event stack in ugfx only allows for a single event to be handled and processed at a time per listener. This is because more arbitrary queuing requires memory allocation of each queue item. This is a speed and ram size problem for an embedded system. It also makes a part of the base GUI non-static allocable which is breaking one of the major design criteria for ugfx. Because of this limitation - if a general click event was generated for say a slider, that slider would not be able to send a new position event as the listener's event slot would already be full with the click event. If the processing was the other way around (click events generated after any widget specific events) you would have strange situations where click events seem to magically disappear - again because the listener's event slot is full. Remember that ugfx works on all sorts of platforms particularly with respect to multi-thread capabilities. Some do not support multi-threading at all (although we internally then create a co-operative threading system for them).

So, generic events just don't work very well on a system designed for embedded use. The code could be added to change the event system but that would make ugfx unsuitable for a lot of platforms and applications that is it currently very suitable for.

I hope that helps you understand some of the basics as to why ugfx is the way it is. The design concepts associated with a GUI on these types of platforms is VERY complex with all sorts of trade-offs between functionality, code complexity and RAM usage.

Link to comment
Share on other sites

Thanks you for patience.

1. You have added to button possibility to be an arrow, to have rounded corners, to be elliptic, to react on keyboard or dial or touch panel. All these possibilities have corresponding defines that can be enabled or disabled. One more define like GDISP_PASSIVE_EVENTS can make possible reacting on events, so no resources will be lost for users who do not need this. This matches your guidelines about flexibility, power and compact code in one box. I do not understand difference between elliptic buttons and label event generation. Just one more feature that can give more flexibility to user.

2. It is not necessary to implement full event stack for window manager, with full path to parents and so on, I know what is embedded and memory limitations. WM already can handle clicks on widget's area, so we can just generate one single event in situation when event not generated now. I have attached patch in previous message, and label generates event without any problem.

3. It is strange to listen reasons about code size, memory limitations and method with replacing WM or custom draw routines in one message. WM can be replaced at runtime, as well as custom draw routines. So I will have in my firmware stock WM compiled in, and stock draw routines compiled in. All this code will not be used but will take place in final firmware. So, size overhead will be more each time we replace some code at runtime.

4. I understand that Studio is beta, but can not agree that Studio can be used only at start point. It looks like Studio will allow full development process in 0.13 - 0.14 (i.e. in a weeks). It will allow possibility to be used in late stages of development, will it be suitable for this or not - it is not so important.

5. I can make myLabel with events, or I can modify core Label. I agree that modifying core code is a bad idea, but as result I will get same problem - I need to change code when I will upgrade uGFX. Or I will need to apply my patch to core Label, or apply changes in core Label to myLabel.

6. Problem with only one event at a time exists now and will exist later - if I will click two buttons at one time and will not detect event in main loop - I will lost one of these events. Label that can generate click event not differs from another button in window.

In other words, there is no need to change event system. Adding events with defines into main repo will not break anything, and will consume no additional resources except few kilobytes for sources on hard drive. Adding events was tested and works well for me. Replacing entire code with another that differs by 1% at runtime - bad idea consuming much more resources in firmware. Adding fullstack events and WM with overlapping objects is not necessary, because now all works well.

I'm too deep in uGFX, so I have to use it.

I will copy-paste widgets into new widgets with events, or will change them in core code - I do not know. It is simpler to change core code (as this already done), I will get no advantages in upgrading if I will make new set of widgets.

I will use labels, progressbars and button as now, one over another, without writing new widget like 'ImageButton with text and progressbars'. Overlapping works fine, I will just react on events in main loop: just one event handler for progressbars, label and its button in switch(). Event generation by labels and progressbars will solve all my problems in GUI building, without need to make new event engine or window manager and without code overheads in firmware.

I'm sure a nice donation of a few thousand dollars would enable Tectu to spend a lot more time on Studio and advance its capability very quickly.

Thank you about mentioning this, but I have no possibility to make such donations (average salary in your country and in my country differs).

I think I wanted too much. Sorry.

Link to comment
Share on other sites

We thank you for using ugfx. We love to get feedback. Ugfx is a spare time hobby for us. Most of our time is spent on earning money for our families or in full time study.

I was just being cheaky with the donation comment. Part of my naughty Australian sense of humour. For commercial usage and larger companies it is sometimes worth them paying money to speed a particular area of interest for them. For mere normal people like us however we know something like that is not possible. We release the source code and make it free for non-commercial use for exactly that reason.

I will look later at your patch and if i think it adds benefit to the whole community and is consistant with the design aims then i will add it. Regardless of whether we do add it or not, we really appreciate your contribution. It is from contributions such as yours that give us ideas and help ugfx progress.

With regard to point 6, the gui has been written very carefully so this is not a problem. The detail is even more complex than the short description provided previously, it is enough to say that part of the design has been very carefully considered and reviewed.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...