Silly demo
Edgar Reynaldo

I made this with Eagle and Allegro 5.

EDIT
Updated demo. Now you can resize and move everything thanks to my WidgetMover class. Wrote it yesterday, ironed the bugs out today.

Download here : Demo2.7z

Everything is done with the mouse. LMB selects. MMB drag scrolls (only the inner window). Hover over different areas to see which widget is in focus, and to see the layering effects. Hover over the border to see the icon change to a grabby hand to move the widget on LMB press, and hover over the margin to see the resize icons.

{"name":"611953","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/1\/117cf8015c51eb6108ba16240442bd18.png","w":1202,"h":941,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/1\/117cf8015c51eb6108ba16240442bd18"}611953 {"name":"611956","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/a\/8ad6c44d2aff28ab0c43292981e7ac0f.png","w":1202,"h":941,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/a\/8ad6c44d2aff28ab0c43292981e7ac0f"}611956

Cleaned up the example code.

#SelectExpand
1 2 3 4#include "Eagle/backends/Allegro5Backend.hpp" 5#include "allegro5/allegro_color.h" 6 7 8 9class TestWidget : public WidgetBase { 10 11 virtual void PrivateDisplay(EagleGraphicsContext* win , int xpos , int ypos); 12 virtual int PrivateHandleEvent(EagleEvent ee); 13 14 virtual void OnFlagChanged(WIDGET_FLAGS f , bool on); 15 16 17public : 18 TestWidget(std::string objname) : 19 WidgetBase("TestWidget" , objname) {} 20 21}; 22 23 24 25void TestWidget::PrivateDisplay(EagleGraphicsContext* win , int xpos , int ypos) { 26 Rectangle r = InnerArea(); 27 r.MoveBy(xpos,ypos); 28 unsigned int flags = Flags(); 29 EagleColor c1 = GetColor(MGCOL); 30 EagleColor c2 = GetColor(BGCOL); 31 if (flags & HASFOCUS) { 32 c1 = GetColor(HLCOL); 33 c2 = GetColor(FGCOL); 34 } 35 win->DrawFilledRectangle(r , (flags & HOVER)?c1:c2); 36 std::string n = ShortName(); 37 win->DrawTextString(win->DefaultFont() , n , InnerArea().CX() , InnerArea().CY() , EagleColor(255,0,0) , HALIGN_CENTER , VALIGN_CENTER); 38} 39 40 41 42int TestWidget::PrivateHandleEvent(EagleEvent ee) { 43 if (ee.type == EAGLE_EVENT_MOUSE_BUTTON_DOWN && ee.mouse.button == 1) { 44 if (OuterArea().Contains(ee.mouse.x , ee.mouse.y)) { 45 return DIALOG_TAKE_FOCUS; 46 } 47 } 48 return DIALOG_OKAY; 49} 50 51 52 53void TestWidget::OnFlagChanged(WIDGET_FLAGS f , bool on) { 54 if (f == HOVER) { 55 EagleLog() << "HOVER changed to " << (on?"on":"off") << std::endl; 56 SetRedrawFlag(); 57 } 58 if (f == HASFOCUS) { 59 EagleLog() << "HASFOCUS changed to " << (on?"on":"off") << std::endl; 60 SetRedrawFlag(); 61 } 62} 63 64 65 66int main(int argc , char** argv) { 67 68 EnableLog(); 69 70 SendOutputToFile("Eagle.log" , "" , false); 71 72 (void)argc; 73 (void)argv; 74 75/// EagleSystem* sys = Eagle::EagleLibrary::System("Allegro5"); 76/// EagleSystem* sys = Eagle::EagleLibrary::System("Allegro5"); 77 Allegro5System* sys = GetAllegro5System(); 78 79 int sw = 1200; 80 int sh = 900; 81 82 if (EAGLE_FULL_SETUP != sys->Initialize(EAGLE_FULL_SETUP)) { 83 EagleWarn() << "Failed to install some components." << std::endl; 84 } 85 EagleGraphicsContext* win = sys->GetWindowManager()->CreateWindow("win" , sw , sh , EAGLE_OPENGL | EAGLE_WINDOWED | EAGLE_RESIZABLE); 86 87 win->Clear(EagleColor(0,255,255)); 88 win->FlipDisplay(); 89 90 std::string bgfile = "stallions.jpg"; 91 EagleImage* bg = win->LoadImageFromFile(bgfile); 92 if (!bg || (bg && !bg->Valid())) { 93 EagleError() << StringPrintF("Failed to load %s from disk.\n" , bgfile.c_str()); 94 return -1; 95 } 96 97 /// Setup some custom colors for our margin, border, and padding 98 SHAREDOBJECT<WidgetColorset> pwc = GetColorsetByName("Default"); 99 EAGLE_ASSERT(pwc); 100 WidgetColorset& wc = *pwc.get(); 101 wc[PADCOL] = EagleColor(127,127,127,255); 102 wc[BORDCOL] = EagleColor(255,255,255,255); 103 wc[MARGCOL] = EagleColor(0,0,0,255); 104 105 106 /// Outer root gui 107 WidgetHandler gui(win , "WidgetHandler" , "GUI1"); 108 gui.SetWidgetArea(WIDGETAREA(10 , 15 , 25 , Rectangle(150,150,900,600)) , false); 109 110 /// A WidgetMover allows us to move any widgets we want 111 WidgetMover wmover("Widget mover"); 112 wmover.SetWidgetArea(Rectangle(-1000,-1000,1,1) , false); 113 wmover.SetHotKey(input_key_held(EAGLE_KEY_LSHIFT) && input_key_press(EAGLE_KEY_ENTER)); 114 wmover.SetAbilities(true , true); 115 116 gui << wmover; 117 118 /// Inner gui 119 WidgetHandler gui2(win , "WidgetHandler" , "GUI2"); 120 gui2.SetupBuffer(1280,960,win); 121 gui2.SetWidgetArea(WIDGETAREA(5,10,15 , Rectangle(130,60,640,480)) , false); 122 gui.AllowMiddleMouseButtonScroll(false); 123 gui2.AllowMiddleMouseButtonScroll(true); 124 125 gui << gui2; 126 127 /// We can have transparent backgrounds in our gui 128 gui.SetBackgroundColor(EagleColor(0,0,0,0)); 129 gui2.SetBackgroundColor(EagleColor(0,0,0,0)); 130 131 /// A RelativeLayout allows us to keep relative positions and sizes of our widgets 132 RelativeLayout rl1("RLAYOUT1"); 133 rl1.Resize(5); 134 rl1.SetLayoutRectangle(0 , LayoutRectangle(0.2 , 0.2 , 0.6 , 0.2)); 135 rl1.SetLayoutRectangle(1 , LayoutRectangle(0.2 , 0.6 , 0.6 , 0.2)); 136 rl1.SetLayoutRectangle(2 , LayoutRectangle(0.4 , 0.2 , 0.2 , 0.6)); 137 rl1.SetLayoutRectangle(3 , LayoutRectangle(0.1 , 0.2 , 0.2 , 0.6)); 138 rl1.SetLayoutRectangle(4 , LayoutRectangle(0.7 , 0.2 , 0.2 , 0.6)); 139 140 gui2.SetRootLayout(&rl1); 141 142 TestWidget tw1("TESTWIDGETH1"); 143 TestWidget tw2("TESTWIDGETH2"); 144 TestWidget tw3("TESTWIDGETV1"); 145 TestWidget tw4("TESTWIDGETV2"); 146 TestWidget tw5("TESTWIDGETV3"); 147 148 rl1.PlaceWidget(&tw1 , 0); 149 rl1.PlaceWidget(&tw2 , 1); 150 rl1.PlaceWidget(&tw3 , 2); 151 rl1.PlaceWidget(&tw4 , 3); 152 rl1.PlaceWidget(&tw5 , 4); 153 154 tw1.SetWidgetArea(WIDGETAREA(tw1.OuterArea() , 3,5,7)); 155 tw2.SetWidgetArea(WIDGETAREA(tw2.OuterArea() , 7,5,3)); 156 tw3.SetWidgetArea(WIDGETAREA(tw3.OuterArea() , 2,4,6)); 157 tw4.SetWidgetArea(WIDGETAREA(tw4.OuterArea() , 6,4,2)); 158 tw5.SetWidgetArea(WIDGETAREA(tw5.OuterArea() , 5,5,5)); 159 160 EagleLog() << "******* SETUP COMPLETE ********" << std::endl; 161 162 bool quit = false; 163 bool redraw = true; 164 165 int mx = 0; 166 int my = 0; 167 168 sys->GetSystemTimer()->Start(); 169 170 while (!quit) { 171 if (redraw) { 172 win->DrawToBackBuffer(); 173 win->Clear(EagleColor(0,0,0)); 174 win->DrawStretched(bg , Rectangle(0 , 0 , sw , sh)); 175 gui.Display(win , 0 , 0); 176/// WidgetBase* hw = gui.GetWidgetAt(mx,my); 177 WidgetBase* hw = wmover.GetMoveWidget(); 178 std::string name = (hw?hw->FullName():"NULL"); 179 win->DrawTextString(win->DefaultFont() , StringPrintF("Widget at %d,%d is [%s]" , mx , my , name.c_str()) , sw - 10 , sh - win->DefaultFont()->Height() - 5 , EagleColor(0,0,0) , HALIGN_RIGHT , VALIGN_TOP); 180 win->FlipDisplay(); 181 redraw = false; 182 } 183 do { 184 EagleEvent ev = sys->WaitForSystemEventAndUpdateState(); 185 if (ev.type != EAGLE_EVENT_TIMER && ev.type != EAGLE_EVENT_MOUSE_AXES) { 186 /// Log non timer and non mouse axes events 187 EagleInfo() << "Event " << EagleEventName(ev.type) << " received in main." << std::endl; 188 } 189 190 /// Event handling 191 if (ev.type == EAGLE_EVENT_DISPLAY_CLOSE) { 192 quit = true; 193 } 194 else if (ev.type == EAGLE_EVENT_KEY_DOWN && ev.keyboard.keycode == EAGLE_KEY_ESCAPE) { 195 quit = true; 196 } 197 else if (ev.type == EAGLE_EVENT_TIMER) { 198 gui.Update(ev.timer.eagle_timer_source->SPT()); 199 redraw = true; 200 } 201 else { 202 gui.HandleEvent(ev); 203 } 204 205 /// Check our gui for messages 206 while (gui.HasMessages()) { 207 WidgetMsg wmsg = gui.TakeNextMessage(); 208 EagleLog() << "Widget Message [" << wmsg << "]" << std::endl; 209 } 210 if (gui.Flags().FlagOn(NEEDS_REDRAW)) { 211 redraw = true; 212 } 213 214 } while (!sys->UpToDate()); 215 } 216 217/// sys->GetSystemQueue()->WaitForEvent(EAGLE_EVENT_KEY_DOWN , 0); 218 219 EagleLog() << "Exited main loop." << std::endl; 220 221/// sys->Shutdown(); 222 atexit(Eagle::EagleLibrary::ShutdownEagle); 223 224 return 0; 225}

Widgets follow the CSS Box model, with a margin, border, and padding surrounding the inner client area. In the left picture, the margin is blue, the border is green, and the padding is red, so you can see it more easily. The right picture looks much better without the coloring though.

Support for attributes is built in.

Eventually I think styling with CSS and scripting with XML will be implemented. That seems to be the direction I'm heading anyway.

bamccaig

...scripting with XML...

{"name":"tenor.gif","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/3\/6392f3acb985a4c0d29c37ba48ad2eed.gif","w":418,"h":234,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/3\/6392f3acb985a4c0d29c37ba48ad2eed"}tenor.gif

I assume you mean layout/content in XML. Scripting in XML, like as in programming in XML, would just be silly. :P

Edgar Reynaldo

Thank you for the correction but don't you have any thing to say about the rest of it?

bamccaig

All that I can really say is that you've done a lot of work on this, and that's great. You should keep it up. I have no immediate need for it, and I think that the learning curve would be quite steep for somebody that did. Also, I think that like most non-trivial software it has some design flaws, but that's to be expected. You should be proud of it and you should continue working on it. I think that a video demo would have been much more informative than still screenshots. My intention is not at all to diminish the work that you have done, and that is why my previous post was so narrow in its scope. I don't have a lot more to say on the rest of it.

The only other thing that I can add is that this sort of redundancy drives me crazy:

Quote:

if (!bg || (bg && !bg->Valid())) {

If !bg failed then bg is implied. When I see this sort of construct I am left to wonder if the author made a mistake because they're repeating themselves, and it's pointless. Of course, we all make mistakes. It's just a pet-peeve because colleagues do this regularly. This can be simplified to:

if (!bg || !bg->Valid()) {

Or, depending on style, though it doesn't aid in keystrokes and generally I don't find that it aides in readability either, you could transform it into this...

if (!(bg && bg->Valid())) {

Perhaps in this case it helps, but it's highly subjective. I appreciate languages that have an unless statement, or at least a more visual/readable not keyword so the operation isn't as easy to overlook. Particularly as our eyes age.

Edgar Reynaldo
bamccaig said:

The only other thing that I can add is that this sort of redundancy drives me crazy:

Edgar Reynaldo said:

if (!bg || (bg && !bg->Valid())) {

Ah, yes, you're correct.

I like your second version the best :

if (!(bg && bg->Valid())) {

bamccaig said:

All that I can really say is that you've done a lot of work on this, and that's great. You should keep it up. I have no immediate need for it, and I think that the learning curve would be quite steep for somebody that did. Also, I think that like most non-trivial software it has some design flaws, but that's to be expected. You should be proud of it and you should continue working on it. I think that a video demo would have been much more informative than still screenshots. My intention is not at all to diminish the work that you have done, and that is why my previous post was so narrow in its scope. I don't have a lot more to say on the rest of it.

Steep learning curve? Perhaps, but there will be full documentation by the time I release it, as well as small tutorials, and a widget creation guide.

Design flaws? What would you change? Or what would you support that I'm not?

I will take your advice about a video demo. I've never recorded video on my laptop before, so that will be an adventure. It's much easier to demonstrate it if you run the example program though, which is why I linked to it.

EDIT
I attached an .mp4 video of the demo running.

bamccaig

Design flaws? What would you change? Or what would you support that I'm not?

I can't say there necessarily are any. I certainly am not familiar enough with it to know them. I think that the flaws will reveal themselves when you try to develop a separate backend for it.

Edgar Reynaldo
bamccaig said:

I can't say there necessarily are any. I certainly am not familiar enough with it to know them. I think that the flaws will reveal themselves when you try to develop a separate backend for it.

Quite right, again. I originally developed Eagle for Allegro 4, and then decided I no longer wanted to be tied down to a single library, as well as reach a larger audience. So I made the abstraction layer, and implemented a driver for Allegro 5. Most of the system and everything is just modeled around Allegro 5 anyway, so when I write the SDL2 driver, I will probably need to refactor everything once more. But for that I would need someone versed in SDL, as I have zero experience with it. I could help them write the driver, but wouldn't know how specific code would have to be implemented.

Anyway, it's growing, and evolving. I'm in a feature freeze right now, for the most part unless there's something really important I'm missing. So that means writing docs and test programs and debugging.

Thank you bambams, for the helpful insight. Appreciated. ;)

8-)

Thread #617783. Printed from Allegro.cc