-
Notifications
You must be signed in to change notification settings - Fork 163
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
mini ui library / util class #15
Comments
The first implementation should be inside https://github.com/Open-Smartwatch/lib-open-smartwatch Moving it to a separate repo can be discussed/done later. |
Shall we add these utilities directly into the "Graphics2DPrint" class ? doesn't seem like a lot of extra features. And do want automatic centering on the whole watch or do we want to center around the position of the cursor only which makes it very easy to get the center of the screen anyway? |
If there are print String related operations, they should go into the Centered around the cursor. This way we can place the cursor, and then select the alignment (left, right (default), centered). |
Are there any class hierarchy ideas already? As far as I see there is only the |
As far as i know not! if u have ideas i'm happy to help implement them! |
Okay, before we dive further into the implementation lets establish some ground "rules"/concepts I would like to follow:
Therefore I propose the following class hierarchy: Any drawable should also get some sort of alignment, so we could set its position e.g. to center (50%, 50%) and it would be centered, as the cursor specifies the center of the screen AND the e.g. image. So maybe an other enum, which addresses stuff like top-left, top-center, top-right, usw.? A stopwatch would therefore create on its loading a new layer, with all the icons usw. and would have to allow the What do you guys think? Yay, a wall of text! And yes, "Dear Imgui" is out there, but it is way more dynamic and therfore needs way more resources during runtime - maybe we could orient ourselfs on their work? |
I like this idea and i think it could be beneficial. I do however not really get how u propose to build it. Also a concern on the memory foodprint. How would u propose to store all the layer information ? It is the drawables std:array right? What is the amount of memory a simple "hello world" string would cost as drawable ? Also main.cpp needs to preform the render which means connecting the "layers" to the gfx_2d library ? or where does the gfx lib fit into the picture? (~~somewhat unexperience programmer, especially in the multiply person project area. (I do however also have a research job that requires me to learn it. so im motivated to learn!)) |
Ouch - give me a hint where I lost you 😀 . I plan to use as much compile-time optimization as possible. So e.g. the icons
Hmm, the
Hmm, such string does not need to be stored inside the drawable - as it is constant anyways the
Everywhere? I do not propose to replace it! Writing the text, setting the cursor and drawing rectangles are still its job. My idea more tries to encapsulate the drawing order (layers) into their own objects. Also the cursor placement is just encapsulated inside the respective drawable, so the dev could just type place a text at 23% width, 24% height and do not need to place the cursor correctly depending on the text size, alignment and the remaining space on the screen. I have to admit that I do not really have an idea what exact features the gfx lib provides (except these fundamental ones). As far as I know the gfx lib does not provide layer support, but I would like to add one, as this simplifies removing and replacing whole parts of the rendering-stack. Want to show a notification? Enable the layer above the app and update the texts! Want to show a little loading-icon above the app? Just swap the respective layer. For example - how does the main work: It goes trough every layer and calls their Also this all should allow us to utilize the two cpu cores we have here (later on). One running the ui render-pipeline when needed and the other one could start taking over background tasks (like managing wifi/ble, running services and therefore updating its own "loading"-layer).
Okay 🤓 - I do work on several projects and have also a job as software developer, BUT this does not mean my ideas are perfect nor appropriate (I do have to admit that I tend to over-engineer stuff)! I do have @max9901 Also when you can speak english, we could chat about all this over on @uvwxy Discord! This way we both know our abilities and can better delegate work. E.g. for #54 @uvwxy works on the ui & server, while I thinker with the compiler, as he has more experience with his own creation, while I wanted to learn more about tl;dr Explanations what I mean and invite for suggestions! |
I'm working on a basic UI helper class right now. let's discuss on discord where we can go from there. :) 👍 |
Any glimbse on this :) ? |
Currently I / we work on the finalization of #54, then I plan to work on #77. @uvwxy will work on other stuff (two services). I then plan to look further into this (I consider this here as a early-stage-draft)... So all the progress is currently the |
I am not sure but i think there will be needs for building Layout on Runtime. I do not see much in the osw_ui.cpp |
I really like the proposed sprite system of #90 I think we should implement possible widges in the same way |
If i did understand it correctly it is quite the same. As i have not found any code, i did start some really really basic test implementation. If u call it Sprite or Drawable - Thats a discussion worth :) If anyone want to look at some testing code just have a look at my UIAstraction branch in /src/ui and apps/tools/ui_test. I have a semi working Drawable/ListView/Label.. more will come if u are interested. |
My recommendation would be to use Sprites as the base class for any UI components. UI Components like Button/Icon/etc would/should have much of the same basic properties as a sprite (position, angle, size, layers, etc) and build on top of it via inheritance. With the Sprite system I also want to add the concept of a |
My recommendation would be the "same" but not call it sprite. In my world a sprite is a 2D Graphic (for example for games). My superclass would be a Drawable as @simonmicro described it and a Sprite is a derviced class which could hold a graphic or animation. I am planning on different Layout components, which could be Grid, VerticalLayout, HorizontalLayout. I have not planned any rotation support for now but surely offset etc if drawables are nested, which u can already see in the ListView i provided. There the nested Items position get controlled by the Listview and the local coords are ignored. I am on planning a UI utility which works really fast on menu/settings/input creation. In my opinion this is a Ui class and sure it can hold Sprite/Icon/Image, call it however you like. A sprite is an image/bitmap and nothing more and should not be a superclass. The base class which holds position/size etc should be something really generic which can than be implement by a sprite, textfield, label, button. Edit: |
Hey, nice seeing you guys working on this! But I would like to add an other thought to the discussion: Please be more static! When you think it is absolutely needed to add dynamical add/remove stuff into the renderer - go for it! But please think twice before proceeding. After all an e.g. MQTT app will know all its label positions during starting and could just show/hide them collectively using e.g. a |
Thats a good thought. Tbh i am "new" to c++ and this level of saving perfomance. |
NP! 😀 A "static" implementation would require you to specify during compile-time what the layers size is, also you would fill such a layer with its constructor and then never be able to "remove"/"add" anything without destroying it. For example - this could it look like: Text t1("wowo", 0.5, 0.5, otherParameters, ...);
Text t2("wowo", 0.5, 0.5, otherParameters, ...);
Layer<2>(t1, t2); Note that we have not used anything on the heap - the example-texts are only on the stack (as we are not using any pointers). The Layer itself gets compiled with enough space to hold two drawable pointers (maybe use std::array under the hood), therefore also gets resolved during compile time and lifes on the stack. A more dynamic implementation would be: Layer l;
Text t1("wowo", 0.5, 0.5, otherParameters, ...);
Text t2("wowo", 0.5, 0.5, otherParameters, ...);
l.add(t1);
l.add(t2); Note there is no limit how many texts the layer could hold and would therefore need to use something like a std::vector and lifes on the heap! With the "static" way the dev, which would use it later on, would be forced from the beginning to know how everything (could) look like and will us reduce headaches later on (like, when I open app A before app B, it crashes with "out of memory" - but app A does clean everything up properly and the free heap space is enough - where is the problem?). Basically on our low-end hardware I would encourage you to use the heap as less as possible. It is convenient, but it tends to get fastly out of hand. Ofc. there is a good chance that I overthink this - feel free to point this out too! |
Thanks for the little excurse :) I am on your side and get your point. |
You seem to be confusing concepts here... A Sprite is just a bitmap, you're correct. And UI elements on an OS are made with bitmaps... Just because game engines "have Sprites" does not mean that an Operating System's UI isn't backed by bitmaps (it is). In Unity, all UI components and Sprites are Behaviors which contain transforms, they are therefore derived from the same concept. In LibGDX Sprites and Widgets aren't exactly the same because UI elements are DOM based. They are rendered completely differently. At the end of the day, all Sprites and UI have positions, angles, layers, etc and ARE bitmaps (all raster images are). Therefore they should come from the same base class even if that base class is not called "Sprite".
I agree, this is a big issue. However, the Stack size isn't that big (I think 8k). So we need to also be careful about what goes on the stack too. My current thought is that larger resources that are contained within an app should mostly be heap bound. That way when the app starts it can alloc the resources and when it stops it can free the resources. Hopefully nothing gets created externally while the app is running. This should (in theory) mean that the heap, in terms of fragmentation, would look the same before app start() and after app stop(). Thoughts on this? |
@SeanReg I think we are talking about the same. And sure, the UI Component in the and is a bitmap, but in the end i think we are justing using other terms and i just would not name the superclass sprite, we can if others think we should :) |
Good point, but do you have further references on that? As far as I know we can use with our stack as much as we want (will be subtracted from the heap) and any stack size limitations for the esp32 are caused by yourself, when you create any
Currently yes? But I would not trust our future selfs to keep that in mind. When I'm thinking about this... What's about the framebuffer management? It should be on the heap and is therefore theoretically able to change over time - I recall @uvwxy saying something about tile based rendering of it? I guess I'll create a service for logging heap sizes asap, so I can monitor the systems usage over time... |
Yes, so this is a little tricky because of the arduino-esp32 framework which we use. When the device boots, a Task is created (loopTask) which the start()/stop()/loop() run in the context of. That task has a fixed stack size: https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/main.cpp However, I agree the precomputed static resources should just come from global memory and not from the context of any Task.
Eh yeah, can't disagree with that one. |
@simonmicro If u have the power to create a service which can monitor heap sizes and idk if possible fragmentation, i could use that to run some tests when i finsh some more complex elements. I am trying to keep thinks on the stack as much as possible without the for now, at least for me, needed dynamic elements or think about it if i can implement them in two ways, like static stack and dynamic heap version which than can be used if really needed. But is it really a problem? As far as i understood if we go in deepsleep the device really shuts down and boots again. Then the heap is rebuild on a new bases (if i understand correctly) and there will be some app switches, but not like running for days. |
Fantastic timing! I've just implemented a new service structure with exactly such a subservice last night (this is WIP, so make sure to not pull any newer versions, otherwise you'll may get the new wifi service :P ): https://github.com/Simonmicro/open-smartwatch-os/tree/feature/wifiService
Yes, but have you noticed the wake up times recently? @uvwxy is currently working on a light sleep version - then we will keep our memory and can directly resume our work after the interrupt! |
tbh. did not use the watch the last days because of the bad wake up times :) will need to try it again. |
I have build a small UI Class/Concept. For now there is a List/Button/Label/Slider: Visuals need some work, but there are some little helpers for width and height for child elements. |
Update : Adjust the size of the flat panel
Add a utility class / libary / .. to collect UI related draw utils
The text was updated successfully, but these errors were encountered: