Search the Community
Showing results for tags 'widget'.
-
I have a parent widget with several children on it. All widgets are custom. MouseDown and MouseUp works without problem for children widgets, but DoubleClick is called only for parent widget when cursor on child widget, except when cursor on top pixel of child widget (y == 0). Why it may happens? Did not reproduce it yet for simple case. When and how exactly DoubleClick is called? Does that depends on other methods like MouseDown, MouseEnter etc.?
-
Bottom border line is pixel lower than should be #include "UltraEngine.h" using namespace UltraEngine; shared_ptr<Window> window; shared_ptr<Framebuffer> framebuffer; shared_ptr<World> menuWold; shared_ptr<Interface> ui; shared_ptr<Camera> uiCamera; void initGui() { auto default_font = LoadFont("Fonts\\arial.ttf"); ui = CreateInterface(menuWold, default_font, framebuffer->GetSize()); ui->SetRenderLayers(2); ui->root->SetColor(0.5f, 0.5f, 0.5f, 1.0f); uiCamera = CreateCamera(menuWold, PROJECTION_ORTHOGRAPHIC); uiCamera->SetPosition((float)framebuffer->GetSize().x * 0.5f, (float)framebuffer->GetSize().y * 0.5f, 0); uiCamera->SetRenderLayers(2); uiCamera->SetClearMode(CLEAR_DEPTH); } int main(int argc, const char* argv[]) { auto displays = GetDisplays(); window = CreateWindow("Ultra Engine", 0, 0, 100, 100, displays[0], WINDOW_DEFAULT); menuWold = CreateWorld(); framebuffer = CreateFramebuffer(window); initGui(); auto btn = CreateButton("", 10, 10, 32, 32, ui->root); while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { menuWold->Update(); menuWold->Render(framebuffer); } return 0; }
-
Hi, I finally managed to build a first release candidate for a SyntaxEditor-Widget. The Widget is using the famous Scintilla TextEditor-Component under the hood and wraps the control into a UAK-Widget. At this point i only provide binaries (includes and libraries) but i am currently preparing to release the source as well. The source itself is semi-autogenerated with a manual created body and a tool which generates the main part of the Scintilla-Component based of so called iFace files maintained by the Scintilla author (these files contains the definitions of each enum or function you can use with Scintilla). Downloads: Demo (Small sample): Demo.zip Libraries and Headers:SyntaxEditor_libinc.zip To use the new widget you need to copy the content of the zip into your project and add the "include" directory to "Additional Include Directories" and add the the path to the Library to "Additional Library Directories" (for Release and Debug configurations). Finally you need to add the needed lib files to "Additional Dependecies": Imm32.lib SyntaxWidget.lib Lexilla.lib Scintilla.lib here is screenshot of the small demo app: and the code: #include "UltraEngine.h" #include "SyntaxWidget.h" #include "ScintillaLexer.hpp" using namespace UltraEngine; int main(int argc, const char* argv[]) { #ifdef _WIN64 auto plugin = LoadPlugin("Plugins/FITextureLoader.*"); #else auto plugin = LoadPlugin("Plugins (x86)/FITextureLoader.*"); #endif if (plugin == NULL) { Print("Failed to load FreeImage plugin."); return 1; } //Get the displays auto displays = GetDisplays(); //Create a window auto window = CreateWindow("Ultra Engine", 0, 0, 800, 600, displays[0], WINDOW_TITLEBAR | WINDOW_RESIZABLE | WINDOW_CENTER); //Create User Interface auto ui = CreateInterface(window); //Create widget auto sz = ui->root->GetSize(); auto toggleVisibility = CreateButton("Visible", 10, 10, 80, 20, ui->root, ButtonStyle::BUTTON_TOGGLE); toggleVisibility->SetState(WidgetState::WIDGETSTATE_SELECTED); auto container = CreatePanel(5, 40, sz.x - 10, sz.y - 45, ui->root, PanelStyle::PANEL_BORDER); sz = container->ClientSize(); container->SetLayout(1, 1, 1, 1); auto syntaxEditor = CreateSyntaxEditor(5, 5, sz.x - 10, sz.y - 10, container); syntaxEditor->SetLayout(1, 1, 1, 1); syntaxEditor->SetFoldFlags(FoldFlag::LineAfterContracted | FoldFlag::LineBeforeContracted); // 16 Draw line below if not expanded //auto lualexer = CreateLexer("lua"); // syntaxEditor->SetILexer(lualexer); auto lexer = CreateLuaLexer(syntaxEditor); syntaxEditor->SetKeyWords(0, "and break do else elseif end for function if in local nil not or repeat return then until while"); syntaxEditor->SetKeyWords(1, "print require"); syntaxEditor->SetProperty("fold", "1"); syntaxEditor->SetProperty("fold.compact", "0"); syntaxEditor->SetAutomaticFold(AutomaticFold::Change | AutomaticFold::Click | AutomaticFold::Show); syntaxEditor->SetMarginSensitiveN(2, 1); auto luasource = R"V0G0N(require("INC_Class.lua") --========================== = cAnimal = setclass("Animal") function cAnimal.methods:init(action, cutename) self.superaction = action self.supercutename = cutename end --========================== cTiger = setclass("Tiger", cAnimal) function cTiger.methods:init(cutename) self : init_super("HUNT (Tiger)", "Zoo Animal (Tiger)") self.action = "ROAR FOR ME!!" self.cutename = cutename function test() end end --========================== Tiger1 = cAnimal:new("HUNT", "Zoo Animal") Tiger2 = cTiger : new("Mr Grumpy") Tiger3 = cTiger : new("Mr Hungry") print("CLASSNAME FOR TIGER1 = ", Tiger1:classname()) print("CLASSNAME FOR TIGER2 = ", Tiger2:classname()) print("CLASSNAME FOR TIGER3 = ", Tiger3:classname()) print("===============") print("SUPER ACTION", Tiger1.superaction) print("SUPER CUTENAME", Tiger1.supercutename) print("ACTION ", Tiger1.action) print("CUTENAME", Tiger1.cutename) print("===============") print("SUPER ACTION", Tiger2.superaction) print("SUPER CUTENAME", Tiger2.supercutename) print("ACTION ", Tiger2.action) print("CUTENAME", Tiger2.cutename) print("===============") print("SUPER ACTION", Tiger3.superaction) print("SUPER CUTENAME", Tiger3.supercutename) print("ACTION ", Tiger3.action) print("CUTENAME", Tiger3.cutename))V0G0N"; String s = luasource; syntaxEditor->SetText(s.c_str()); syntaxEditor->StyleSetBack(STYLE_DEFAULT, RGB(syntaxEditor->color[WIDGETCOLOR_BACKGROUND].r * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].g * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].b * 255)); syntaxEditor->StyleSetFore(STYLE_DEFAULT, RGB(syntaxEditor->color[WIDGETCOLOR_FOREGROUND].r * 255, syntaxEditor->color[WIDGETCOLOR_FOREGROUND].g * 255, syntaxEditor->color[WIDGETCOLOR_FOREGROUND].b * 255)); syntaxEditor->StyleSetFont(STYLE_DEFAULT, "Consolas"); syntaxEditor->StyleSetSize(STYLE_DEFAULT, 11); syntaxEditor->StyleClearAll(); syntaxEditor->SetCaretFore(RGB(syntaxEditor->color[WIDGETCOLOR_FOREGROUND].r * 255, syntaxEditor->color[WIDGETCOLOR_FOREGROUND].g * 255, syntaxEditor->color[WIDGETCOLOR_FOREGROUND].b * 255)); syntaxEditor->SetFoldMarginHiColour(true, RGB(syntaxEditor->color[WIDGETCOLOR_HIGHLIGHT].r * 255, syntaxEditor->color[WIDGETCOLOR_HIGHLIGHT].g * 255, syntaxEditor->color[WIDGETCOLOR_HIGHLIGHT].b * 255)); syntaxEditor->SetFoldMarginColour(true, RGB(syntaxEditor->color[WIDGETCOLOR_HIGHLIGHT].r * 255, syntaxEditor->color[WIDGETCOLOR_HIGHLIGHT].g * 255, syntaxEditor->color[WIDGETCOLOR_HIGHLIGHT].b * 255)); auto textWidth = syntaxEditor->TextWidth(STYLE_LINENUMBER, "_99999"); syntaxEditor->SetMargins(5); syntaxEditor->SetMarginTypeN(0, MarginType::Number); syntaxEditor->SetMarginWidthN(0, textWidth); syntaxEditor->SetMarginTypeN(2, MarginType::Symbol); syntaxEditor->SetMarginMaskN(2, SC_MASK_FOLDERS); syntaxEditor->SetMarginWidthN(2, 16); syntaxEditor->SetMarginLeft(2); syntaxEditor->SetMarginRight(2); syntaxEditor->MarkerDefine(SC_MARKNUM_FOLDER, MarkerSymbol::BoxPlus); syntaxEditor->MarkerDefine(SC_MARKNUM_FOLDEROPEN, MarkerSymbol::BoxMinus); syntaxEditor->MarkerDefine(SC_MARKNUM_FOLDEREND, MarkerSymbol::BoxPlus); syntaxEditor->MarkerDefine(SC_MARKNUM_FOLDERMIDTAIL, MarkerSymbol::TCorner); syntaxEditor->MarkerDefine(SC_MARKNUM_FOLDEROPENMID, MarkerSymbol::BoxMinusConnected); syntaxEditor->MarkerDefine(SC_MARKNUM_FOLDERSUB, MarkerSymbol::VLine); syntaxEditor->MarkerDefine(SC_MARKNUM_FOLDERTAIL, MarkerSymbol::LCornerCurve); for (int i = 25; i <= 31; i++) { syntaxEditor->MarkerSetFore(i, RGB(syntaxEditor->color[WIDGETCOLOR_BACKGROUND].r * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].g * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].b * 255)); syntaxEditor->MarkerSetBack(i, RGB(215, 221, 232)); } syntaxEditor->StyleSetFore(LuaLexer::WORD, RGB(150, 190, 177)); syntaxEditor->StyleSetFore(LuaLexer::WORD2, RGB(220, 220, 170)); syntaxEditor->StyleSetFore(LuaLexer::COMMENT, RGB(87, 160, 61)); syntaxEditor->StyleSetFore(LuaLexer::COMMENTLINE, RGB(87, 160, 61)); syntaxEditor->StyleSetFore(LuaLexer::COMMENTDOC, RGB(87, 160, 61)); syntaxEditor->StyleSetFore(LuaLexer::CHARACTER, RGB(87, 160, 61)); syntaxEditor->StyleSetFore(LuaLexer::STRING, RGB(214, 151, 108)); syntaxEditor->StyleSetBack(STYLE_LINENUMBER, RGB(syntaxEditor->color[WIDGETCOLOR_BACKGROUND].r * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].g * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].b * 255)); syntaxEditor->StyleSetFore(STYLE_LINENUMBER, RGB(43, 145, 175)); syntaxEditor->SetElementColour(Element::ListBack, RGB(syntaxEditor->color[WIDGETCOLOR_BACKGROUND].r * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].g * 255, syntaxEditor->color[WIDGETCOLOR_BACKGROUND].b * 255)); syntaxEditor->SetElementColour(Element::List, RGB(syntaxEditor->color[WIDGETCOLOR_FOREGROUND].r * 255, syntaxEditor->color[WIDGETCOLOR_FOREGROUND].g * 255, syntaxEditor->color[WIDGETCOLOR_FOREGROUND].b * 255)); syntaxEditor->SetElementColour(Element::ListSelected, RGB(syntaxEditor->color[WIDGETCOLOR_SELECTEDTEXT].r * 255, syntaxEditor->color[WIDGETCOLOR_SELECTEDTEXT].g * 255, syntaxEditor->color[WIDGETCOLOR_SELECTEDTEXT].b * 255)); syntaxEditor->SetElementColour(Element::ListSelectedBack, RGB(syntaxEditor->color[WIDGETCOLOR_SELECTION].r * 255, syntaxEditor->color[WIDGETCOLOR_SELECTION].g * 255, syntaxEditor->color[WIDGETCOLOR_SELECTION].b * 255)); auto pixmap = LoadPixmap("Resources/class.png")->Resize(16, 16); syntaxEditor->RGBAImageSetWidth(pixmap->size.x); syntaxEditor->RGBAImageSetHeight(pixmap->size.y); syntaxEditor->RegisterRGBAImage(1, pixmap->pixels->Data()); while (true) { const Event ev = WaitEvent(); if (ev.id == SyntaxEditor::EVENT_CHARADDED) { auto notification = static_cast<TextEditorNotification*>(ev.extra.get()); if (notification->ch == '.' && !syntaxEditor->AutoCActive()) { syntaxEditor->AutoCShow(0, "Entity?1 Window?1 Hello World"); } } switch (ev.id) { case EVENT_WIDGETACTION: if (ev.source == toggleVisibility) { if (toggleVisibility->GetState() == WidgetState::WIDGETSTATE_SELECTED) { toggleVisibility->SetText("Visible"); syntaxEditor->Show(); } else { toggleVisibility->SetText("Hidden"); syntaxEditor->Hide(); } } break; case EVENT_WIDGETSELECT: break; case EVENT_QUIT: case EVENT_WINDOWCLOSE: return 0; break; default: break; } } return 0; } ToDo: Publish the source add helper to apply UAK based theming move some Scintilla-Types to UAK-Types (e.g.: Colour to iVec4) I hope you enjoy the release and i look forward for any suggestions and feedback is very welcome.
- 2 comments
-
- 4
-
- ultraappkit
- uak
-
(and 6 more)
Tagged with:
-
In this first entry I will introduce some basics about the internal structure of the Widget class and what the purpose of some of its members is. For the real basics on how to write a custom Widget I suggest reading this https://www.ultraengine.com/learn/CPP/CustomWidgets first. Most of the members are self explained, so I will focus in this entry on 4 important methods: virtual bool Initialize(const WString& text, const int x, const int y, const int width, const int height, shared_ptr<Widget> parent, const int style); virtual void UpdateLayout(); virtual void Draw(const int x, const int y, const int width, const int height); virtual void Draw__(const int x, const int y, const int width, const int height); The "Initialize" method: As the name says, this method initialize the Widget. In this method you can define additional parameters, the block size needed for the drawing etc. This method should always be used in the custom Create-Function and unless really needed it should not be overridden or at least the base method should be called like this: bool CustomWidget::Initialize(const WString& text, const int x, const int y, const int width, const int height, shared_ptr<Widget> parent, const int style) { if (Widget::Initialize(text, x, y, width, height, parent, style)) { //your initialisation goes here } } Internally, the "Initialize" method setups the initial size, the parent, style and text. The "UpdateLayout" method: This method is called everytime the position or the size of the widget changes and can be overridden to support custom layouting. When overridden keep in mind that this method is dependend on the "SetLayout" method, so you should either call the base method to support the current layout settings and update the Clientsizes or you need to calculate it by yourself. In this method you can calculate or maintain a list of visible children which can later be used in the Draw__ method. The "Draw" method: This method is normally the most common one to override as this method defines how the widget is shown on screen and is called everytime the widget is redrawn. The drawing in the UltraAppKit is defined by Blocks, these blocks are drawn in order and for speed you should consider to update the block structure when the layout changes or events need a visual feedback: virtual void MouseEnter(const int x, const int y) { hover = true; Redraw(); } //Called each time the widget is redrawn virtual void Draw(const int x, const int y, const int width, const int height) { blocks.clear(); Vec4 color = Vec4(1, 0, 0, 1); if (hover) color = Vec4(0, 1, 0, 1); //Background rectangle AddBlock(iVec2(0), this->size, color); //Foreground text AddBlock(text, iVec2(0), this->size, Vec4(1), TEXT_CENTER | TEXT_MIDDLE); } I will explain the "Draw"-Method with the "Blocks"-Structure in depth in a later entry. The "Draw__" method: This method is not documented and may be subject to change, but this method is very important in case you want to write something which needs more in depth handling over the drawing itself. Like the "Draw"-Method this is called as well when the widget needs to be redrawn. From my observations this is the internal main entry point to the Redraw-Chain it is important to at least call the own "Draw"-Method here. This method also needs to call the Draw__ of each of its kids so that these are drawn as well. In this method you can limit the children which are drawn on screen when you maintain a visibility list in the UpdateLayout method. More on this in a later entry. What comes next: This is just a short overview from my own observations and some info might be incorrect or change in the future. The following entries will explain more in depth details about writing a custom widget with some hints and tips I came across I am currently developing a small library of custom widgets myself which will include at least the following: Layout: FlowLayoutPanel (ready) StackPanel (ready) GridLayoutPanel (in progress) Other: ContentPanel (a control host with automatic content scrolling) TextEditor (based on Scintilla, in Progress) and more (you can suggest widgets you might need, and I will see what I can do) here is a small code sample how the GridLayoutPanel (and a preview of the TextEditor) works and how it looks: auto layout = CreateGridLayoutPanel(0, mainmenu->size.y, sz.x, sz.y- mainmenu->size.y, ui->root); layout->SetLayout(1, 1, 1, 1); layout->AddRowDefinition(GridLength::PIXEL, TOOLBARHEIGHT); layout->AddRowDefinition(GridLength::STAR); layout->AddRowDefinition(GridLength::PIXEL, CONSOLEHEIGHT - 28); layout->AddRowDefinition(GridLength::PIXEL, 28); layout->AddRowDefinition(GridLength::PIXEL, STATUSBARHEIGHT); layout->AddColumnDefinition(GridLength::STAR,3); layout->AddColumnDefinition(GridLength::STAR,1); auto toolbar = CreatePanel(0, 0, 0, 0, layout); toolbar->SetColor(1, 1, 0); auto statusbar = CreatePanel(0, 0,0,0, layout); statusbar->SetColor(0, 1, 0); auto mainpanel = CreatePanel(0, 0, 0, 0, layout); mainpanel->SetColor(0, 0, 1); auto sidepanel = CreatePanel(0, 0, 0, 0, layout); sidepanel->SetColor(1, 0, 0); auto consolepanel = CreatePanel(0, 0, 0, 0, layout); consolepanel->SetColor(0.5, 1, 0); auto inputpanel = CreatePanel(0, 0, 0, 0, layout); inputpanel->SetColor(0.3, 1, 0.5); layout->AssignChild(toolbar, 0, 0, 2); //Assign toolbar to grid col 0 and row 0 with a columnspan of 2 layout->AssignChild(statusbar, 0, 4, 2);//Assign statusbar to grid col 0 and row 4 with a columnspan of 2 layout->AssignChild(mainpanel, 0, 1);//Assign mainpanel to grid col 0 and row 1 layout->AssignChild(sidepanel, 1, 1, 1, 3); //Assign sidepanel to grid col 1 and row 1 with a rowspan of 2 layout->AssignChild(consolepanel, 0, 2);//Assign consolepanel to grid col 0 and row 2 layout->AssignChild(inputpanel, 0, 3);//Assign inputpanel to grid col 0 and row 3 layout->UpdateLayout(); auto mpcs = mainpanel->ClientSize(); auto editor = CreateTextEditor(0, 0, mpcs.x, mpcs.y, mainpanel); editor->SetLayout(1, 1, 1, 1); auto textWidth = editor->TextWidth(STYLE_LINENUMBER, "_99999"); editor->SetMargins(5); editor->SetMarginTypeN(0,MarginType::Number); editor->SetMarginWidthN(0,textWidth); editor->SetMarginTypeN( 2, MarginType::Symbol); editor->SetMarginMaskN( 2, SC_MASK_FOLDERS); editor->SetMarginWidthN( 2, 20); editor->MarkerDefine( SC_MARKNUM_FOLDER,MarkerSymbol::BoxPlusConnected); editor->MarkerDefine( SC_MARKNUM_FOLDEROPEN, MarkerSymbol::BoxMinusConnected); editor->MarkerDefine( SC_MARKNUM_FOLDEREND, MarkerSymbol::BoxPlus); editor->MarkerDefine( SC_MARKNUM_FOLDERMIDTAIL, MarkerSymbol::TCorner); editor->MarkerDefine( SC_MARKNUM_FOLDEROPENMID, MarkerSymbol::BoxMinusConnected); editor->MarkerDefine( SC_MARKNUM_FOLDERSUB, MarkerSymbol::VLine); editor->MarkerSetBack(SC_MARKNUM_FOLDERSUB, RGB(128,128,128)); editor->MarkerDefine( SC_MARKNUM_FOLDERTAIL, MarkerSymbol::LCorner); editor->MarkerSetBack(SC_MARKNUM_FOLDERMIDTAIL, RGB(128, 128, 128)); editor->MarkerSetBack(SC_MARKNUM_FOLDERSUB, RGB(128, 128, 128)); editor->MarkerSetBack(SC_MARKNUM_FOLDERTAIL, RGB(128, 128, 128)); editor->SetFoldFlags(FoldFlag::LineAfterContracted); // 16 Draw line below if not expanded auto lualexer = CreateLexer("lua"); editor->SetILexer(lualexer); editor->StyleSetFore(SCE_LUA_WORD, RGB(0,0,255)); editor->StyleSetFore(SCE_LUA_WORD2, RGB(0, 128, 128)); editor->StyleSetFore(SCE_LUA_COMMENT, RGB(0, 255, 0)); editor->StyleSetFore(SCE_LUA_COMMENTLINE, RGB(0, 255, 0)); editor->StyleSetFore(SCE_LUA_COMMENTDOC, RGB(0, 255, 0)); editor->StyleSetFore(SCE_LUA_CHARACTER, RGB(255, 0, 0)); editor->StyleSetFore(SCE_LUA_STRING, RGB(255, 0, 0)); editor->SetKeyWords( 0, "and break do else elseif end for function if in local nil not or repeat return then until while"); editor->SetKeyWords(1, "print require"); editor->SetProperty( "fold", "1"); editor->SetAutomaticFold(AutomaticFold::Change | AutomaticFold::Click | AutomaticFold::Show); editor->SetMarginSensitiveN( 2, 1);
- 2 comments
-
- 6