diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..c2dbd15e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +# Allow custom line endings during checkout, but enforce LF on checkin +*.cc text +*.c text +*.hh text +*.h text + +*.py text +*.md text + +*.txt text + +*.bml binary + diff --git a/src/opengl/AutoNavBar.cc b/src/opengl/AutoNavBar.cc new file mode 100644 index 00000000..12424504 --- /dev/null +++ b/src/opengl/AutoNavBar.cc @@ -0,0 +1,71 @@ +#include "opengl/AutoNavBar.hh" + +using namespace std; + +AutoNavBar::AutoNavBar(GLWin* w, float x, float y, float axisPadding, + float horizontalPadding, float verticalPadding, + bool isVertical, bool isReverseOrder) + : NavigationBar(w, x, y, 0, 0, axisPadding, isVertical), + horizontalPadding(horizontalPadding), + verticalPadding(verticalPadding), + isReverseOrder(isReverseOrder) { + w->autoNavBar = this; +} + +void AutoNavBar::addButton(Member* m) { + int index = buttons.size(); + ButtonWidget* bw = NavigationBar::addButton(m->getName(), "action"); + bw->setAction(bind(&GLWin::switchTab, parentWin, index)); + + if (isReverseOrder) { + reverseButtonOrder(); + c->getGuiText()->clear(); + } + + fitBarDimensions(horizontalPadding, verticalPadding); + drawBarBox(); +} + +void AutoNavBar::reverseButtonOrder() { + float currentX = xPos; + float currentY = yPos; + for (int i = buttons.size() - 1; i >= 0; i--) { + if (isVertical) { + buttons[i]->setY(currentY); + currentY += buttons[i]->getH() + axisPadding; + } else { + buttons[i]->setX(currentX); + currentX += buttons[i]->getW() + axisPadding; + } + } +} + +void AutoNavBar::fitBarDimensions(float widthPadding, float heightPadding) { + if (isVertical) { + barWidth = buttonsWidth() + widthPadding; + barHeight = buttonsLength() + heightPadding; + } else { + barWidth = buttonsLength() + widthPadding; + barHeight = buttonsWidth() + heightPadding; + } +} + +float AutoNavBar::buttonsLength() { + if (isVertical) { + if (isReverseOrder) { + return buttons.front()->getY() + buttons.front()->getH() - + buttons.back()->getY(); + } else { + return buttons.back()->getY() + buttons.back()->getH() - + buttons.front()->getY(); + } + } else { + if (isReverseOrder) { + return buttons.front()->getX() + buttons.front()->getW() - + buttons.back()->getX(); + } else { + return buttons.back()->getX() + buttons.back()->getW() - + buttons.front()->getX(); + } + } +} \ No newline at end of file diff --git a/src/opengl/AutoNavBar.hh b/src/opengl/AutoNavBar.hh new file mode 100644 index 00000000..7ed23a12 --- /dev/null +++ b/src/opengl/AutoNavBar.hh @@ -0,0 +1,69 @@ +#pragma once + +#include "opengl/NavigationBar.hh" + +/** + * @brief Version of NavigationBar in which new buttons are automatically added + * when a new member is added. The dimensions of the buttons and the navigation + * bar are also automatically determined and updated. An AutoNavBar should be + * added to a window BEFORE any other members. + * + */ +class AutoNavBar : public NavigationBar { + private: + bool isReverseOrder; + float horizontalPadding, verticalPadding; + + public: + /** + * @brief Create a new automated navigation bar + * + * @param w The initial window to draw on + * @param x x-coordinate of top-left corner + * @param y y-coordinate of top-left corner + * @param axisPadding distance between the edges of two buttons + * @param horizontalPadding horizontal distance between buttons and bar edge + * @param verticalPadding vertical distance between buttons and bar edge + * @param isVertical allow vertical navigation bars (e.x. Ubuntu's task bar) + * @param isReverseOrder display buttons in the reverse order the members are + * added (leftmost/topmost button corresponds to first member displayed) + */ + AutoNavBar(GLWin* w, float x, float y, float axisPadding, + float horizontalPadding, float verticalPadding, + bool isVertical = false, bool isReverseOrder = false); + + /** + * @brief Add a button to the nav bar for a new member + * + * @param m pointer to member + */ + void addButton(Member* m); + + /** + * @brief Update the positions of all buttons in the nav bar such that their + * displayed left-to-right/top-to-bottom order is opposite that of their index + * order + * + */ + void reverseButtonOrder(); + + /** + * @brief Updates the dimensions of the nav bar to fit around the buttons. + * Option to add padding between the buttons and nav bar edges. Override of + * fitBarDimensions function from NavigationBar that accounts for + * isReverseOrder + * + * @param widthPadding horizontal distance between nav bar edge and closest + * button + * @param heightPadding vertical distance between nav bar edge and closest + * button + */ + void fitBarDimensions(float widthPadding = 0, float heightPadding = 0); + + /** + * @brief Calculates and returns the lengthwise distance of the list of + * buttons in the nav bar. Override of buttonsLength function from + * NavigationBar that accounts for isReverseOrder + */ + float buttonsLength(); +}; \ No newline at end of file diff --git a/src/opengl/ButtonWidget.cc b/src/opengl/ButtonWidget.cc index 39b9f43a..eb1d185d 100644 --- a/src/opengl/ButtonWidget.cc +++ b/src/opengl/ButtonWidget.cc @@ -24,17 +24,25 @@ void ButtonWidget::click(float mouseX, float mouseY) { void ButtonWidget::init() {} -ButtonWidget::ButtonWidget(MainCanvas* c, float x, float y, float w, float h, +ButtonWidget::ButtonWidget(MainCanvas* c, const Style* s, float x, float y, + float w, float h, const std::string& text, + const char action[]) + : InteractiveWidget2D(c, s, x, y, w, h), text(text) { + redraw(); +} + +ButtonWidget::ButtonWidget(MainCanvas* c, const Style* s, float x, float y, const std::string& text, const char action[]) - : InteractiveWidget2D(c, x, y, w, h), text(text) { + : InteractiveWidget2D(c, s, x, y, s->f->getWidth(text), s->f->getHeight()), + text(text) { redraw(); } void ButtonWidget::redraw() { - int borderSize = 2; + float borderSize = s->lineWidth; m->fillRectangle(x - borderSize, y - borderSize, w + (borderSize * 2), - h + (borderSize * 2), grail::black); - m->fillRectangle(x, y, w, h, grail::red); - t->addCentered(x, y, w, h, c->getStyle()->f, text); + h + (borderSize * 2), s->bg); + m->fillRectangle(x, y, w, h, s->fg); + t->addCentered(x, y, w, h, s->f, text); } \ No newline at end of file diff --git a/src/opengl/ButtonWidget.hh b/src/opengl/ButtonWidget.hh index 30e368f1..b9842fa6 100644 --- a/src/opengl/ButtonWidget.hh +++ b/src/opengl/ButtonWidget.hh @@ -12,10 +12,13 @@ class ButtonWidget : public InteractiveWidget2D { std::optional> func; public: - ButtonWidget(MainCanvas* c, float x, float y, float w, float h, - const std::string& text, const char action[]); - ButtonWidget(StyledMultiShape2D* m, MultiText* t, float x, float y, float w, + ButtonWidget(MainCanvas* c, const Style* s, float x, float y, float w, float h, const std::string& text, const char action[]); + ButtonWidget(StyledMultiShape2D* m, MultiText* t, const Style* s, float x, + float y, float w, float h, const std::string& text, + const char action[]); + ButtonWidget(MainCanvas* c, const Style* s, float x, float y, + const std::string& text, const char action[]); void click(float mouseX, float mouseY) override; void init() override; @@ -25,4 +28,13 @@ class ButtonWidget : public InteractiveWidget2D { void setAction(Func func) { this->func = func; } + + void updateCanvas(MainCanvas* canvas) { c = canvas; }; + + float getX() { return x; }; + void setX(float newX) { x = newX; }; + float getY() { return y; }; + void setY(float newY) { y = newY; }; + float getW() { return w; }; + float getH() { return h; }; }; \ No newline at end of file diff --git a/src/opengl/CMakeLists.txt b/src/opengl/CMakeLists.txt index 47b3361c..ca3bc092 100644 --- a/src/opengl/CMakeLists.txt +++ b/src/opengl/CMakeLists.txt @@ -1,4 +1,5 @@ set(grail-opengl + AutoNavBar.cc AxisWidget.cc BarChartWidget.cc BoxChartWidget.cc @@ -8,6 +9,7 @@ set(grail-opengl Colors.cc Document.cc DocView.cc + DropDownMenu.cc ErrNames.cc ESRIPolygon.cc ESRIShape.cc diff --git a/src/opengl/Canvas.cc b/src/opengl/Canvas.cc index 58da4f3e..e6d5dad1 100644 --- a/src/opengl/Canvas.cc +++ b/src/opengl/Canvas.cc @@ -17,6 +17,13 @@ Canvas::Canvas(Tab* tab) : Canvas(tab->getParentWin(), tab) {} Canvas::~Canvas() { cleanup(); } +void MainCanvas::copy(const MainCanvas& orig) { + gui = orig.gui; + guiText = orig.guiText; + menu = orig.menu; + menuText = orig.menuText; +} + void Canvas::cleanup() { for (uint32_t i = 0; i < layers.size(); i++) delete layers[i]; layers.clear(); @@ -86,8 +93,9 @@ void MainCanvas::init() { menuText->init(); tab->registerCallback(Tab::Inputs::MOUSE0_PRESS, "Widget Callback- Press", Tab::Security::SAFE, bind(&MainCanvas::click, this)); - tab->registerCallback(Tab::Inputs::MOUSE0_RELEASE, "Widget Callback- Release", - Tab::Security::SAFE, bind(&MainCanvas::click, this)); + // tab->registerCallback(Tab::Inputs::MOUSE0_RELEASE, "Widget Callback- + // Release", + // Tab::Security::SAFE, bind(&MainCanvas::click, this)); } void MainCanvas::render() { diff --git a/src/opengl/Canvas.hh b/src/opengl/Canvas.hh index 6eaf6596..28a0b7dd 100644 --- a/src/opengl/Canvas.hh +++ b/src/opengl/Canvas.hh @@ -54,7 +54,7 @@ class Canvas { // z!=0 } ~Canvas(); - Canvas(const Canvas& orig) = delete; + Canvas(const Canvas&) = delete; Canvas& operator=(const Canvas& orig) = delete; uint32_t getWidth() const { return vpW; } uint32_t getHeight() const { return vpH; } @@ -126,6 +126,7 @@ class MainCanvas : public Canvas { ~MainCanvas(); MainCanvas(const MainCanvas&) = delete; MainCanvas& operator=(const MainCanvas&) = delete; + void copy(const MainCanvas&); StyledMultiShape2D* getGui() { return gui; } MultiText* getGuiText() { return guiText; } StyledMultiShape2D* getMenu() { return menu; } diff --git a/src/opengl/DropDownMenu.cc b/src/opengl/DropDownMenu.cc new file mode 100644 index 00000000..3323d757 --- /dev/null +++ b/src/opengl/DropDownMenu.cc @@ -0,0 +1,82 @@ +#include "opengl/DropDownMenu.hh" + +#include + +DropDownMenu::DropDownMenu(GLWin* w, float x, float y, float menuWidth, + float menuHeight, const char label[], + float axisPadding, Style* buttonStyle, + bool isVertical) + : Member(w->getSharedMenuTab(), "DDMenu", 0), + w(w), + buttonStyle(buttonStyle), + isVertical(isVertical), + isOpen(false) { + menuButton = new ButtonWidget(tab->getMainCanvas(), buttonStyle, x, y, label, + "open menu"); + menuButton->setAction([this]() { this->openClose(); }); + + if (isVertical) { + nav = new NavigationBar(w, x, y + menuButton->getH(), menuWidth, menuHeight, + axisPadding, isVertical); + } else { + nav = new NavigationBar(w, x + menuButton->getW(), y, menuWidth, menuHeight, + axisPadding, isVertical); + } + nav->setButtonStyle(buttonStyle->f, buttonStyle->bg, buttonStyle->fg, + buttonStyle->lineWidth); +} + +// TODO: fix menu breaking when isReverseOrder is true +DropDownMenu::DropDownMenu(GLWin* w, float x, float y, const char label[], + float axisPadding, float menuHorizontalPadding, + float menuVerticalPadding, Style* buttonStyle, + bool isVertical, bool isReverseOrder) + : Member(w->getSharedMenuTab(), "DDMenu", 0), + w(w), + buttonStyle(buttonStyle), + isVertical(isVertical), + isOpen(false) { + menuButton = new ButtonWidget(tab->getMainCanvas(), buttonStyle, x, y, label, + "open menu"); + menuButton->setAction([this]() { this->openClose(); }); + + if (isVertical) { + nav = new AutoNavBar(w, x, y + menuButton->getH(), axisPadding, + menuHorizontalPadding, menuVerticalPadding, isVertical, + isReverseOrder); + } else { + nav = new AutoNavBar(w, x + menuButton->getW(), y, axisPadding, + menuHorizontalPadding, menuVerticalPadding, isVertical, + isReverseOrder); + } + nav->setButtonStyle(buttonStyle->f, buttonStyle->bg, buttonStyle->fg, + buttonStyle->lineWidth); +} + +void DropDownMenu::openMenu() { + std::cout << "Opening menu!" << std::endl; + isOpen = true; +} +void DropDownMenu::closeMenu() { + std::cout << "Closing menu!" << std::endl; + isOpen = false; + + MainCanvas* c = w->getSharedTab()->getMainCanvas(); + c->getGui()->clear(); + c->getGuiText()->clear(); +} + +/* +void DropDownMenu::setButtonStyle(const Font* f, glm::vec4 borderColor, + glm::vec4 buttonColor, + float borderThickness) { + buttonStyle->f = f; + buttonStyle->bg = borderColor; + buttonStyle->fg = buttonColor; + buttonStyle->lineWidth = borderThickness; + + c->getGuiText()->clear(); + menuButton->redraw(); + nav->setButtonStyle(f, borderColor, buttonColor, borderThickness); +} +*/ \ No newline at end of file diff --git a/src/opengl/DropDownMenu.hh b/src/opengl/DropDownMenu.hh new file mode 100644 index 00000000..e94f34e9 --- /dev/null +++ b/src/opengl/DropDownMenu.hh @@ -0,0 +1,40 @@ +#pragma once + +#include "opengl/AutoNavBar.hh" + +class DropDownMenu : public Member { + private: + NavigationBar* nav; + ButtonWidget* menuButton; + GLWin* w; + bool isVertical, isOpen; + Style* buttonStyle; + + public: + DropDownMenu(GLWin* w, float x, float y, float menuWidth, float menuHeight, + const char label[], float axisPadding, + Style* buttonStyle = new Style(FontFace::get("TIMES", 20, + FontFace::BOLD), + grail::black, grail::red, 1), + bool isVertical = true); + DropDownMenu(GLWin* w, float x, float y, const char label[], + float axisPadding, float menuHorizontalPadding, + float menuVerticalPadding, + Style* buttonStyle = new Style(FontFace::get("TIMES", 20, + FontFace::BOLD), + grail::black, grail::red, 1), + bool isVertical = true, bool isReverseOrder = false); + void openMenu(); + void closeMenu(); + void openClose() { + if (isOpen) { + closeMenu(); + } else { + openMenu(); + } + }; + /* + void setButtonStyle(const Font* f, glm::vec4 borderColor, + glm::vec4 buttonColor, float borderThickness); + */ +}; \ No newline at end of file diff --git a/src/opengl/GLWin.cc b/src/opengl/GLWin.cc index feb3f7a3..83df5e17 100644 --- a/src/opengl/GLWin.cc +++ b/src/opengl/GLWin.cc @@ -94,6 +94,8 @@ void GLWin::keyCallback(GLFWwindow *win, int key, int scancode, int action, int mods) { uint32_t input = (mods << 11) | (action << 9) | key; cerr << "key: " << key << " mods: " << mods << " input=" << input << '\n'; + winMap[win]->sharedTab->doit(input); + winMap[win]->sharedMenuTab->doit(input); winMap[win]->currentTab()->doit(input); } @@ -107,6 +109,8 @@ void GLWin::mouseButtonCallback(GLFWwindow *win, int button, int action, uint32_t input = (mods << 9) | (action << 3) | button; fmt::print("mouse!{}, action={}, location=({}, {}), input={}\n", button, action, w->mouseX, w->mouseY, input); + winMap[win]->sharedTab->doit(input); + winMap[win]->sharedMenuTab->doit(input); winMap[win]->currentTab()->doit(input); } @@ -114,6 +118,8 @@ void GLWin::scrollCallback(GLFWwindow *win, double xoffset, double yoffset) { // cout << "xoffset=" << xoffset << " yoffset=" << yoffset << '\n'; // todo: we would have to copy offsets into the object given the way this is uint32_t input = 400; + winMap[win]->sharedTab->doit(input + int(yoffset)); + winMap[win]->sharedMenuTab->doit(input + int(yoffset)); winMap[win]->currentTab()->doit(input + int(yoffset)); } @@ -165,7 +171,8 @@ GLWin::GLWin(uint32_t bgColor, uint32_t fgColor, const string &title, faces(16), dragMode(false), mousePressX(0), - mousePressY(0) { + mousePressY(0), + autoNavBar(nullptr) { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); @@ -247,8 +254,10 @@ void GLWin::startWindow() { guiTextStyle = new Style(guiFont, 0.5, 0.5, 0.5, 0, 0, 0, 1, COMMON_SHADER); menuStyle = new Style(menuFont, 0.5, 0.5, 0.5, 0, 0, 0, 1, COMMON_SHADER); menuTextStyle = new Style(menuFont, 0.5, 0.5, 0.5, 0, 0, 0, 1, COMMON_SHADER); - tabs.add(new Tab(this)); - current = 0; + sharedTab = new Tab(this); + sharedMenuTab = new Tab(this); + // tabs.add(new Tab(this)); + current = -1; hasBeenInitialized = true; } void GLWin::baseInit() { @@ -272,6 +281,8 @@ void GLWin::baseInit() { for (int i = 0; i < tabs.size(); ++i) { tabs[i]->init(); } + sharedMenuTab->init(); + sharedTab->init(); } int GLWin::init(GLWin *g, uint32_t w, uint32_t h, uint32_t exitAfter) { @@ -300,15 +311,23 @@ void GLWin::cleanup() { delete tabs[i]; // TODO:cw[i]->cleanup(); } tabs.clear(); + delete sharedTab; + sharedTab = nullptr; + delete sharedMenuTab; + sharedMenuTab = nullptr; delete defaultStyle; defaultStyle = nullptr; Shader::cleanAll(); } void GLWin::init() {} -void GLWin::render() { currentTab()->render(); } +void GLWin::render() { + if (current >= 0) currentTab()->render(); +} // default is no animation. Override if you want your class to animate -void GLWin::update() { currentTab()->update(); } +void GLWin::update() { + if (current >= 0) currentTab()->update(); +} // declare prototype access to static function in other file which calls // FaceFont::cleanup() @@ -349,6 +368,8 @@ void GLWin::mainLoop() { bgColor.a); // Clear the colorbuffer and depth glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); render(); + sharedTab->render(); + sharedMenuTab->render(); renderTime += glfwGetTime() - startRender; glfwSwapBuffers(win); // Swap buffer so the scene shows on screen if (frameCount >= 150) { @@ -367,10 +388,14 @@ void GLWin::mainLoop() { } currentTab()->tick(); // update time in current tab for any models using // simulation time + sharedTab->tick(); + sharedMenuTab->tick(); needsUpdate = false; glfwPollEvents(); // Check and call events // note: any events needing a refresh should set dirty = true if (currentTab()->checkUpdate()) setUpdate(); + if (sharedTab->checkUpdate()) setUpdate(); + if (sharedMenuTab->checkUpdate()) setUpdate(); if (needsUpdate) { update(); needsRender = true; diff --git a/src/opengl/GLWin.hh b/src/opengl/GLWin.hh index d9bdc860..6be71017 100644 --- a/src/opengl/GLWin.hh +++ b/src/opengl/GLWin.hh @@ -12,6 +12,7 @@ #include "opengl/GLWinFonts.hh" #include "opengl/Shader.hh" #include "util/DynArray.hh" +#include "util/Ex.hh" #include "util/HashMap.hh" class GLFWwindow; // forward declaration, simplify: include file not needed // here @@ -22,6 +23,7 @@ class Style; class Font; class XDLIterator; class MainCanvas; +class AutoNavBar; class GLWin { protected: @@ -52,8 +54,10 @@ class GLWin { uint32_t frameNum; double lastRenderTime; // Stores last time of render char frameName[32]; + Tab* sharedTab; // For nav bars + Tab* sharedMenuTab; // For buttons that open/close menus DynArray tabs; // list of web pages, ie tabs - uint32_t current; // current (active) tab + int32_t current; // current (active) tab void checkUpdate(); public: @@ -65,6 +69,7 @@ class GLWin { uint32_t width, height; // width and height of the window in pixels bool needsUpdate, needsRender; bool focused; + AutoNavBar* autoNavBar; uint32_t exitAfter; // if not zero, will terminate private: @@ -123,9 +128,19 @@ class GLWin { } MainCanvas* getMainCanvas(); - Tab* currentTab() { return tabs[current]; } + constexpr Tab* currentTab() { + if (current != -1) { + return tabs[current]; + } else { + throw Ex2( + Errcode::UNDEFINED, + "A tab must be created before trying to access the current tab"); + } + } + constexpr Tab* getSharedTab() { return sharedTab; } + constexpr Tab* getSharedMenuTab() { return sharedMenuTab; } - void setSize(uint32_t w, uint32_t h) { + constexpr void setSize(uint32_t w, uint32_t h) { width = w; height = h; } @@ -187,5 +202,7 @@ Shape* pick(int x, int y, Shape*); // click on (x,y), get Shape behind void prevTab(); Tab* addTab(); void removeTab(); + void switchTab(int tabIndex) { current = tabIndex; }; + void toLastTab() { current = tabs.size() - 1; }; void goToLink(const char ipaddr[], uint16_t port, uint32_t requestID); }; diff --git a/src/opengl/GLWinFonts.cc b/src/opengl/GLWinFonts.cc index 032beb8f..394aea57 100644 --- a/src/opengl/GLWinFonts.cc +++ b/src/opengl/GLWinFonts.cc @@ -197,6 +197,10 @@ float Font::getWidth(const char text[], uint32_t len) const { return w; } +float Font::getWidth(const string& text) const { + return getWidth(text.c_str(), text.length()); +} + FontFace::FontFace(FT_Library ft, const string& faceName, const string& facePath, uint32_t minFontSize, uint32_t inc, uint32_t maxFontSize, uint8_t bitmap[], uint32_t& sizeX, diff --git a/src/opengl/GLWinFonts.hh b/src/opengl/GLWinFonts.hh index f44024de..f9701781 100644 --- a/src/opengl/GLWinFonts.hh +++ b/src/opengl/GLWinFonts.hh @@ -140,6 +140,7 @@ class Font { return textureId; } // get the texture shared by all Fonts within the FontFace float getWidth(const char text[], const uint32_t len) const; + float getWidth(const std::string& text) const; friend std::ostream& operator<<(std::ostream& s, const Font& f) { return s << "Font height=" << f.height << " numGlyphs=" << f.glyphs.size(); // return s << "Font " << f.parentFace->faceName << " height=" << f.height diff --git a/src/opengl/GraphStyle.hh b/src/opengl/GraphStyle.hh index e23b3754..75200465 100644 --- a/src/opengl/GraphStyle.hh +++ b/src/opengl/GraphStyle.hh @@ -30,9 +30,20 @@ class GraphStyle : public Member { float pointSize; public: + /** + * @brief Construct a new Graph Style object + * + * A graph style provides a series of defaults for drawing graphs and their + * components + * + * @param tab A tab to add the graph style to + * @param faceName name of the font face + * @param titleSize size of the title font + * @param axisSize size of the axis font + */ GraphStyle(Tab* tab, const char faceName[], uint32_t titleSize, - uint32_t axisSize) - : Member(tab), + uint32_t axisSize, const char name[]) + : Member(tab, name), // two lines and the overall title baseStyle(faceName, axisSize, 1, 0, 0, 0, 0.3, 0.3, 0.3, 5), titleStyle(faceName, titleSize, 1, 0, 0, 0, 0, 0, 0, 5), @@ -64,6 +75,25 @@ class GraphStyle : public Member { barOutlineColors = {grail::gray, grail::black, grail::yellow}; } + /** + * @brief Construct a new Graph Style object, by creating a new tab + * + * A graph style provides a series of defaults for drawing graphs and their + * components + * + * TODO: See if this can use Member's GLWin constructor instead of manually + * adding a new tab. I had a feeling doing so would lead to double + * construction. + * + * @param w A window to draw on + * @param faceName name of the font face + * @param titleSize size of the title font + * @param axisSize size of the axis font + */ + GraphStyle(GLWin* w, const char faceName[], uint32_t titleSize, + uint32_t axisSize, const char name[]) + : GraphStyle(w->addTab(), faceName, titleSize, axisSize, name) {} + /** * @brief Summary * @details Description diff --git a/src/opengl/InteractiveWidget2D.hh b/src/opengl/InteractiveWidget2D.hh index 32cefc0c..65b51643 100644 --- a/src/opengl/InteractiveWidget2D.hh +++ b/src/opengl/InteractiveWidget2D.hh @@ -10,12 +10,15 @@ class InteractiveWidget2D : public Widget2D { protected: MainCanvas* c; + const Style* s; bool isPressed; public: - InteractiveWidget2D(MainCanvas* c, float x, float y, float w, float h) + InteractiveWidget2D(MainCanvas* c, const Style* s, float x, float y, float w, + float h) : Widget2D(c->getGui(), c->getGuiText(), x, y, w, h), c(c), + s(s), isPressed(false) { c->addClickableWidget(this); } diff --git a/src/opengl/Main.cc b/src/opengl/Main.cc index 6afb5bbd..f87c12f3 100644 --- a/src/opengl/Main.cc +++ b/src/opengl/Main.cc @@ -4,13 +4,12 @@ using namespace std; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab); +void grailmain(int argc, char* argv[], GLWin* w); int main(int argc, char* argv[]) { try { GLWin w(1024, 800, 0xFFFFFFFF, 0x000000FF, "Grail Window"); - Tab* tab = w.currentTab(); - grailmain(argc, argv, &w, tab); + grailmain(argc, argv, &w); w.mainLoop(); // g->t = thread(crun, g); // TODO: move this to GLWin::cleanup or destructor? FontFace::emptyFaces(); diff --git a/src/opengl/Member.cc b/src/opengl/Member.cc index 0dd6b3ad..fc391b3a 100644 --- a/src/opengl/Member.cc +++ b/src/opengl/Member.cc @@ -1,18 +1,27 @@ +#include "opengl/AutoNavBar.hh" #include "opengl/GrailGUI.hh" using namespace std; // BUG: If Frame Rate exceeds refresh rate (noticed at 120fps where // default is 60fps), animation breaks at the Tab level -Member::Member(Tab* tab, double frameRate, double dt) - : tab(tab), c(tab->getMainCanvas()) { +Member::Member(Tab* tab, string name, double frameRate, double dt) + : tab(tab), c(tab->getMainCanvas()), name(name) { tab->setFrameRate(frameRate); tab->setDt(dt); tab->setDefaultDt(0.0001); tab->addMember(this); + + GLWin* w = tab->getParentWin(); + if (w->autoNavBar != nullptr) { + w->autoNavBar->addButton(this); + } } +Member::Member(GLWin* w, string name, double frameRate, double dt) + : Member(w->addTab(), name, frameRate, dt) {} + void Member::setFrameRate(double frameRate) { tab->setFrameRate(frameRate); } void Member::setModelDt(double dt, double defaultDt) { @@ -20,6 +29,9 @@ void Member::setModelDt(double dt, double defaultDt) { tab->setDefaultDt(defaultDt); } +string Member::getName() { return name; }; +void Member::setName(string newName) { name = newName; }; + void Member::init() {} void Member::render() {} void Member::update() {} diff --git a/src/opengl/Member.hh b/src/opengl/Member.hh index e5a14802..83749b33 100644 --- a/src/opengl/Member.hh +++ b/src/opengl/Member.hh @@ -11,13 +11,20 @@ class Member { protected: Tab* tab; MainCanvas* c; + std::string name; public: - Member(Tab* tab, double frameRate = -1, double dt = 0.0001); + Member(Tab* tab, std::string name = "Member", double frameRate = -1, + double dt = 0.0001); + Member(GLWin* w, std::string name = "Member", double frameRate = -1, + double dt = 0.0001); void setFrameRate(double frameRate); void setModelDt(double dt, double defaultDt); + std::string getName(); + void setName(std::string newName); + // Allow members to override init, render, and update // Tabs iterate through each of these manually diff --git a/src/opengl/NavigationBar.cc b/src/opengl/NavigationBar.cc index ce2ad3ba..0e204eb9 100644 --- a/src/opengl/NavigationBar.cc +++ b/src/opengl/NavigationBar.cc @@ -10,72 +10,160 @@ using namespace std; // TODO: make this confirm to some design guide, maybe use material's design // guide on tabs? -NavigationBar::NavigationBar(MainCanvas* initialCanvas, - const Style* initialStyle, float x, float y, +NavigationBar::NavigationBar(MainCanvas* initialCanvas, float x, float y, float width, float height, float axisPadding, bool isVertical) - : Member(initialCanvas->getTab()), - currentCanvas(initialCanvas), - m(initialCanvas, initialStyle), - t(initialCanvas, initialStyle), + : Member(initialCanvas->getTab(), "NavBar", 0), + c(initialCanvas), + parentWin(initialCanvas->getWin()), xPos(x), yPos(y), barWidth(width), barHeight(height), axisPadding(axisPadding), isVertical(isVertical) { - canvases.insert(initialCanvas); + buttonStyle = + new Style(parentWin->getMenuFont(), grail::black, grail::red, 1); + barStyle = new Style(parentWin->getMenuFont(), grail::black, grail::gray, 1); - this->isVertical = isVertical; + /* defaultButtonHeight = min(48_f32, height); defaultButtonWidth = min(90_f32, width); defaultEdgeWidth = min(16_f32, width / 3); addButton(defaultButtonWidth, defaultButtonHeight, axisPadding, "+", - "add tab") - .setAction(bind(&NavigationBar::addTab, this)); + "add tab") + .setAction(bind(&NavigationBar::addTab, this)); + */ } -NavigationBar::NavigationBar(Tab* initialTab, float x, float y, float width, +NavigationBar::NavigationBar(GLWin* w, float x, float y, float width, float height, float axisPadding, bool isVertical) - : NavigationBar{initialTab->getMainCanvas(), - initialTab->getMainCanvas()->getStyle(), - x, - y, - width, - height, - axisPadding, - isVertical} { - parentWin = initialTab->getParentWin(); -} + : NavigationBar(w->getSharedTab()->getMainCanvas(), x, y, width, height, + axisPadding, isVertical) {} -ButtonWidget& NavigationBar::addButton(float width, float height, - float axisOffset, string label, +ButtonWidget* NavigationBar::addButton(float width, float height, string label, const char action[]) { - buttons.emplace_back(currentCanvas, xPos, yPos, width, height, label, action); - buttons.back().setStyledMultiShape(&m); - buttons.back().setMultiText(&t); - buttons.back().redraw(); + if (isVertical) { + buttons.push_back(new ButtonWidget(c, buttonStyle, xPos, + yPos + axisOffset(), width, height, + label, action)); + } else { + buttons.push_back(new ButtonWidget(c, buttonStyle, xPos + axisOffset(), + yPos, width, height, label, action)); + } return buttons.back(); } -void NavigationBar::addTab() { - Tab* t = parentWin->addTab(); - t->addMember(this); - reparentButtons(t->getMainCanvas()); - t->setUpdate(); - t->setRender(); +ButtonWidget* NavigationBar::addButton(string label, const char action[]) { + if (isVertical) { + buttons.push_back(new ButtonWidget(c, buttonStyle, xPos, + yPos + axisOffset(), label, action)); + } else { + buttons.push_back(new ButtonWidget(c, buttonStyle, xPos + axisOffset(), + yPos, label, action)); + } + return buttons.back(); } -void NavigationBar::reparentButtons(MainCanvas* c) { - if (canvases.find(c) == canvases.end()) { - c->addLayer(&m); - c->addLayer(&t); - canvases.insert(c); +float NavigationBar::axisOffset() { + if (buttons.empty()) { + return 0; + } + + if (isVertical) { + return buttons.back()->getY() + buttons.back()->getH() + axisPadding; + } else { + return buttons.back()->getX() + buttons.back()->getW() + axisPadding; } - for (ButtonWidget& b : buttons) { - c->addClickableWidget(&b); +} + +void NavigationBar::setButtonAction( + int buttonIndex, std::optional> func) { + buttons[buttonIndex]->setAction(func); +} + +void NavigationBar::setButtonStyle(const Font* f, glm::vec4 borderColor, + glm::vec4 buttonColor, + float borderThickness) { + buttonStyle->f = f; + buttonStyle->bg = borderColor; + buttonStyle->fg = buttonColor; + buttonStyle->lineWidth = borderThickness; +} + +void NavigationBar::setBarStyle(glm::vec4 borderColor, glm::vec4 barColor, + float borderThickness) { + barStyle->bg = borderColor; + barStyle->fg = barColor; + barStyle->lineWidth = borderThickness; +} + +void NavigationBar::drawBarBox() { + StyledMultiShape2D* m = c->getGui(); + float borderSize = barStyle->lineWidth; + m->fillRectangle(xPos - borderSize, yPos - borderSize, + barWidth + (borderSize * 2), barHeight + (borderSize * 2), + barStyle->bg); + m->fillRectangle(xPos, yPos, barWidth, barHeight, barStyle->fg); + + for (ButtonWidget* b : buttons) { + b->redraw(); } } +void NavigationBar::fitBarDimensions(float widthPadding, float heightPadding) { + if (isVertical) { + barWidth = buttonsWidth() + widthPadding; + barHeight = buttonsLength() + heightPadding; + } else { + barWidth = buttonsLength() + widthPadding; + barHeight = buttonsWidth() + heightPadding; + } +} + +float NavigationBar::buttonsLength() { + if (isVertical) { + return buttons.back()->getY() + buttons.back()->getH() - + buttons.front()->getY(); + } else { + return buttons.back()->getX() + buttons.back()->getW() - + buttons.front()->getX(); + } +} + +float NavigationBar::buttonsWidth() { + float width; + if (isVertical) { + width = buttons[0]->getW(); + for (ButtonWidget* b : buttons) { + width = max(b->getW(), width); + } + + } else { + width = buttons[0]->getH(); + for (ButtonWidget* b : buttons) { + width = max(b->getH(), width); + } + } + return width; +} + +/* +void NavigationBar::addNewTab() { + Tab* t = parentWin->addTab(); + // canvases.insert(t->getMainCanvas()); + // addToTab(t); +} + +void NavigationBar::addToTab(Tab* tab) { + tab->addMember(this); + MainCanvas* newCanvas = tab->getMainCanvas(); + canvases.insert(newCanvas); + newCanvas->copy(*currentCanvas); + tab->setUpdate(); + tab->setRender(); +} +*/ + void NavigationBar::balanceButtons(int numButtons) {} \ No newline at end of file diff --git a/src/opengl/NavigationBar.hh b/src/opengl/NavigationBar.hh index ed8159dc..b0e05222 100644 --- a/src/opengl/NavigationBar.hh +++ b/src/opengl/NavigationBar.hh @@ -1,23 +1,22 @@ #pragma once +#include #include #include "opengl/ButtonWidget.hh" class NavigationBar : public Member { - private: - std::vector buttons; - std::unordered_set canvases; + protected: + std::vector buttons; GLWin* parentWin; - MainCanvas* currentCanvas; - StyledMultiShape2D m; - MultiText t; + MainCanvas* c; float defaultButtonWidth; float defaultButtonHeight; float defaultEdgeWidth; Style* buttonStyle; + Style* barStyle; float xPos, yPos, barWidth, barHeight, axisPadding; bool isVertical; @@ -33,15 +32,14 @@ class NavigationBar : public Member { * @param axisPadding distance between the edges of two buttons * @param isVertical allow vertical navigation bars (e.x. Ubuntu's task bar) */ - NavigationBar(MainCanvas* initialCanvas, const Style* initialStyle, float x, - float y, float width, float height, float axisPadding, - bool isVertical); + NavigationBar(MainCanvas* initialCanvas, float x, float y, float width, + float height, float axisPadding, bool isVertical); public: /** * @brief Create a new (horizontal or vertical) navigation bar * - * @param initialTab The initial tab to draw on + * @param w The initial window to draw on * @param x x-coordinate of top-left corner * @param y y-coordinate of top-left corner * @param width width of navigation bar @@ -49,48 +47,122 @@ class NavigationBar : public Member { * @param axisPadding distance between the edges of two buttons * @param isVertical allow vertical navigation bars (e.x. Ubuntu's task bar) */ - NavigationBar(Tab* initialTab, float x, float y, float width, float height, + NavigationBar(GLWin* w, float x, float y, float width, float height, float axisPadding, bool isVertical = false); /** - * @brief Create a new button and return a reference to it + * @brief Create a new button and return a pointer to it * * @param width width of the new button * @param height height of the new button - * @param axisOffset offset relative to the previous button * @param label the text to be shown on the button * @param action a description of the button's action - * @return ButtonWidget& a reference to the new button + * @return ButtonWidget* a pointer to the new button */ - ButtonWidget& addButton(float width, float height, float axisOffset, - std::string label, const char action[]); + ButtonWidget* addButton(float width, float height, std::string label, + const char action[]); /** - * @brief Balance n buttons on the nav bar + * @brief Create a new button and return a pointer to it. Button + * width/height are automatically determined based on the text and buttonStyle + * font * - * This is particularly useful in scenarios where a screen can fit n tabs and - * there are m tabs that could be displayed (n < m). In this case, the - * NavigationBar will determine the ideal placement of each button such that - * at most numButtons will be displayed at a given time. + * @param label the text to be shown on the button + * @param action a description of the button's action + * @return ButtonWidget* a pointer to the new button + */ + ButtonWidget* addButton(std::string label, const char action[]); + + /** + * @brief Automatically calculate and return the axis offset for new button on + * nav bar * - * @param numButtons number of buttons to display */ - void balanceButtons(int numButtons); + float axisOffset(); /** - * @brief Allows the buttons to be reparented to a new MainCanvas + * @brief Set an action for a button in the nav bar * - * This function uses the fact that each InteractiveWidget2D, and therefore - * each Widget2D can use a custom StyledMultiShape2D and MultiText to swap - * over to a new MainCanvas and redraw each shape. + * @param buttonIndex index of button in buttons vector + * @param func function call for action + */ + void setButtonAction(int buttonIndex, + std::optional> func); + + /** + * @brief Redefine the style of all buttons in the nav bar * - * @param c + * @param f font of button text + * @param borderColor color of button border + * @param buttonColor main color of button + * @param borderThickness thickness of button border */ - void reparentButtons(MainCanvas* c); + void setButtonStyle(const Font* f, glm::vec4 borderColor, + glm::vec4 buttonColor, float borderThickness); /** - * @brief Adds a new tab to the window and adds the navigation bar to the tab + * @brief Redefine the style for the nav bar box + * + * @param borderColor color of box border + * @param barColor main color of box + * @param borderThickness thickness of box border + */ + void setBarStyle(glm::vec4 borderColor, glm::vec4 barColor, + float borderThickness); + + /** + * @brief Draw a box around the dimension of the nav bar * */ - void addTab(); + void drawBarBox(); + + /** + * @brief Updates the dimensions of the nav bar to fit around the buttons. + * Option to add padding between the buttons and nav bar edges + * + * @param widthPadding horizontal distance between nav bar edge and closest + * button + * @param heightPadding vertical distance between nav bar edge and closest + * button + */ + void fitBarDimensions(float widthPadding = 0, float heightPadding = 0); + + /** + * @brief Calculates and returns the lengthwise distance of the list of + * buttons in the nav bar + */ + float buttonsLength(); + + /** + * @brief Calculates and returns the crosswise distance of the list of + * buttons in the nav bar + */ + float buttonsWidth(); + + /** + * @brief Balance n buttons on the nav bar + * + * This is particularly useful in scenarios where a screen can fit n tabs + * and there are m tabs that could be displayed (n < m). In this case, the + * NavigationBar will determine the ideal placement of each button such + * that at most numButtons will be displayed at a given time. + * + * @param numButtons number of buttons to display + */ + void balanceButtons(int numButtons); + + MainCanvas* getCanvas() { return c; }; + + /** + * @brief Adds a new tab to the window and adds the navigation bar to the tab + * + * + /* + void addNewTab(); + + void addToTab(Tab* tab); + void render() { + std::cout << "printing from NavigationBar::render()" << std::endl; + } + */ }; \ No newline at end of file diff --git a/src/opengl/Widget2D.hh b/src/opengl/Widget2D.hh index 4846cbee..8817a20d 100644 --- a/src/opengl/Widget2D.hh +++ b/src/opengl/Widget2D.hh @@ -1,25 +1,25 @@ -#pragma once -#include "opengl/GrailGUI.hh" - -/* - Represent a compound object to be drawn using StyledMultiShape2D and MultiText - -*/ - -class StyledMultiShape2D; -class MultiText; - -class Widget2D { - protected: - StyledMultiShape2D* m; - MultiText* t; - float x, y; // top left corner of the widget on the screen - float w, h; // width and height of the widget - public: - Widget2D(StyledMultiShape2D* m, MultiText* t, float x, float y, float w, - float h) - : m(m), t(t), x(x), y(y), w(w), h(h) {} - void setStyledMultiShape(StyledMultiShape2D* m) { this->m = m; } - void setMultiText(MultiText* t) { this->t = t; } - virtual void init() = 0; -}; +#pragma once +#include "opengl/GrailGUI.hh" + +/* + Represent a compound object to be drawn using StyledMultiShape2D and MultiText + +*/ + +class StyledMultiShape2D; +class MultiText; + +class Widget2D { + protected: + StyledMultiShape2D* m; + MultiText* t; + float x, y; // top left corner of the widget on the screen + float w, h; // width and height of the widget + public: + Widget2D(StyledMultiShape2D* m, MultiText* t, float x, float y, float w, + float h) + : m(m), t(t), x(x), y(y), w(w), h(h) {} + void setStyledMultiShape(StyledMultiShape2D* m) { this->m = m; } + void setMultiText(MultiText* t) { this->t = t; } + virtual void init() = 0; +}; diff --git a/src/util/Callbacks.cc b/src/util/Callbacks.cc index 77f0e213..860eafdd 100644 --- a/src/util/Callbacks.cc +++ b/src/util/Callbacks.cc @@ -4,13 +4,11 @@ using namespace std; -CallbackHandler::CallbackHandler() { +CallbackHandler::CallbackHandler() : actionNameMap(64, 4096) { + inputMap.fill(0); for (int i = 0; i < 3; i++) numActions[i] = 1; } -HashMap CallbackHandler::actionNameMap(64, 4096); -std::array inputMap(); - uint32_t CallbackHandler::internalRegisterAction(const char name[], Security s, function action) { uint32_t securityIndex = uint32_t(s); diff --git a/src/util/Callbacks.hh b/src/util/Callbacks.hh index c237cf8e..b31e869a 100644 --- a/src/util/Callbacks.hh +++ b/src/util/Callbacks.hh @@ -22,13 +22,13 @@ class CallbackHandler { template using CallbackFunc = void (T::*)(void); - inline static std::array inputMap; + std::array inputMap; /* map an integer code to a function to execute the actions are all the publicly available performance the code can DO */ - inline static std::array, 4096> actionMap; - static HashMap actionNameMap; + std::array, 4096> actionMap; + HashMap actionNameMap; uint32_t lookupAction(const char actionName[]); // static GLWin* w; void setEvent(uint32_t e, uint32_t a) { inputMap[e] = a; } diff --git a/test/2d/testDisplayBook.cc b/test/2d/testDisplayBook.cc index b5e7c900..d02539f4 100644 --- a/test/2d/testDisplayBook.cc +++ b/test/2d/testDisplayBook.cc @@ -11,7 +11,7 @@ class BookViewer : public Member { const char *filename; public: - BookViewer(Tab *tab, const char filename[]); + BookViewer(GLWin *w, const char filename[]); void advance(); void back(); @@ -41,8 +41,8 @@ void BookViewer::bottom() { tab->setRender(); } -BookViewer::BookViewer(Tab *tab, const char filename[]) - : Member(tab), filename(filename) { +BookViewer::BookViewer(GLWin *w, const char filename[]) + : Member(w), filename(filename) { tab->bindEvent(264, &BookViewer::bottom, this); tab->bindEvent(265, &BookViewer::top, this); tab->bindEvent(262, &BookViewer::advance, this); @@ -68,7 +68,7 @@ BookViewer::BookViewer(Tab *tab, const char filename[]) // c->addLayer(new Image(400, 400, 400, 400, "res/trumpmelania.png", s)); } -void grailmain(int argc, char *argv[], GLWin *w, Tab *defaultTab) { +void grailmain(int argc, char *argv[], GLWin *w) { const char *filename = argc < 2 ? "res/Annatest.txt" : argv[1]; - new BookViewer(defaultTab, filename); + new BookViewer(w, filename); } diff --git a/test/2d/testStyledMultishape.cc b/test/2d/testStyledMultishape.cc index 26bd628f..efeb1b5b 100644 --- a/test/2d/testStyledMultishape.cc +++ b/test/2d/testStyledMultishape.cc @@ -5,7 +5,7 @@ using namespace std; using namespace grail; class TestStyledMultishape : public Member { public: - TestStyledMultishape(Tab* tab) : Member(tab, 0, 0) { + TestStyledMultishape(GLWin* w) : Member(w, 0, 0) { MainCanvas* c = tab->getMainCanvas(); StyledMultiShape2D* gui = c->getGui(); @@ -48,9 +48,9 @@ class TestStyledMultishape : public Member { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Test StyledMultiShape"); - new TestStyledMultishape(defaultTab); + new TestStyledMultishape(w); } #if 0 diff --git a/test/2d/testText3.cc b/test/2d/testText3.cc index d19adc38..c4f48993 100644 --- a/test/2d/testText3.cc +++ b/test/2d/testText3.cc @@ -48,7 +48,7 @@ class TestText3 : public Member { return yStart + 50; } - TestText3(Tab* tab) : Member(tab, 0, 0.1) { + TestText3(GLWin* w) : Member(w, 0, 0.1) { Canvas* c = tab->getMainCanvas(); uint32_t width = c->getWidth(), height = c->getHeight(); @@ -72,7 +72,7 @@ class TestText3 : public Member { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Test Text3"); - new TestText3(defaultTab); + new TestText3(w); } diff --git a/test/2d/testTriangle.cc b/test/2d/testTriangle.cc index f5a33a0a..e7237f5e 100644 --- a/test/2d/testTriangle.cc +++ b/test/2d/testTriangle.cc @@ -5,7 +5,7 @@ using namespace grail; class TestTriangle : public Member { public: - TestTriangle(Tab* tab) : Member(tab, 0, 0) {} + TestTriangle(GLWin* w) : Member(w, 0, 0) {} void init() { MainCanvas* c = tab->getMainCanvas(); @@ -15,7 +15,7 @@ class TestTriangle : public Member { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Solar System"); - new TestTriangle(defaultTab); + new TestTriangle(w); } diff --git a/test/3d/Globe.cc b/test/3d/Globe.cc index 666eca22..68d59bb3 100644 --- a/test/3d/Globe.cc +++ b/test/3d/Globe.cc @@ -10,7 +10,7 @@ class Globe : public Member { float earthRotationAngle; public: - Globe(Tab* tab) : Member(tab, 0, 0.1) { + Globe(GLWin* w) : Member(w, 0, 0.1) { earthRotationAngle = .01; Canvas* c = tab->getMainCanvas(); Camera* cam = c->setLookAtProjection(2, 3, 40, 0, 0, 0, 0, 0, 1); @@ -26,7 +26,7 @@ class Globe : public Member { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Globe"); - new Globe(defaultTab); + new Globe(w); } diff --git a/test/3d/SolarSystem.cc b/test/3d/SolarSystem.cc index 5e9244d3..23fde2df 100644 --- a/test/3d/SolarSystem.cc +++ b/test/3d/SolarSystem.cc @@ -86,9 +86,8 @@ class SolarSystem : public Member { constexpr static double SIDEREAL_DAY = 0.9972; // number of 24-hour "days" it takes earth to rotate once public: - SolarSystem(Tab* tab) : Member(tab, 0, .0125), bodies(10) { + SolarSystem(GLWin* w) : Member(w, 0, .0125), bodies(10) { cam = c->setLookAtProjection(2, 3, 40, 0, 0, 0, 0, 0, 1); - GLWin* w = tab->getParentWin(); const Style* s = w->getDefaultStyle(); const Font* font = w->getDefaultFont(); defineBindings(); @@ -153,7 +152,7 @@ void SolarSystem::defineBindings() { tab->bindEvent(Tab::Inputs::HOME, &Tab::gotoStartTime, tab); } -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Solar System"); - new SolarSystem(defaultTab); + new SolarSystem(w); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 05fb3811..8c5ee346 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,47 +1,47 @@ - -# add_grail_executable([BINNAME ] SRC LIBS ) - -# 2D Graphics -add_subdirectory(2d) - -# 3D Graphics -add_subdirectory(3d) - -# CAD -add_subdirectory(CAD) - -# Graphs -add_subdirectory(graph) - -# GUI -add_subdirectory(gui) - -# Maps -add_subdirectory(maps) - - -# Media -add_subdirectory(media) - -# Networking - -# Solar System -add_subdirectory(solarsystem) - -# Util - -# XDL -add_subdirectory(xdl) - -# XP (Experimental) -add_subdirectory(xp) - -# Unsorted -# add_grail_executable(SRC ../src/xp/decompressBlockLoader.cc LIBS grail lzma) -# add_grail_executable(SRC StockDemo.cc LIBS grail) - - - - - - + +# add_grail_executable([BINNAME ] SRC LIBS ) + +# 2D Graphics +add_subdirectory(2d) + +# 3D Graphics +add_subdirectory(3d) + +# CAD +add_subdirectory(CAD) + +# Graphs +add_subdirectory(graph) + +# GUI +add_subdirectory(gui) + +# Maps +add_subdirectory(maps) + + +# Media +add_subdirectory(media) + +# Networking + +# Solar System +add_subdirectory(solarsystem) + +# Util + +# XDL +add_subdirectory(xdl) + +# XP (Experimental) +add_subdirectory(xp) + +# Unsorted +# add_grail_executable(SRC ../src/xp/decompressBlockLoader.cc LIBS grail lzma) +# add_grail_executable(SRC StockDemo.cc LIBS grail) + + + + + + diff --git a/test/graph/testBarChart.cc b/test/graph/testBarChart.cc index 10bb30b2..6a15b960 100644 --- a/test/graph/testBarChart.cc +++ b/test/graph/testBarChart.cc @@ -7,7 +7,7 @@ using namespace grail; class TestBarChart : public GraphStyle { public: - TestBarChart(Tab* tab) : GraphStyle(tab, "TIMES", 20, 12) { + TestBarChart(GLWin* w) : GraphStyle(w, "TIMES", 20, 12, "Bar Chart") { MainCanvas* c = tab->getMainCanvas(); vector values = {4, 6, 8, 10, 12, 14}; vector logValues = {4, 8, 16, 32, 64, 128}; @@ -57,7 +57,7 @@ class TestBarChart : public GraphStyle { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* tab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Test Bar Chart"); - tab->addMember(new TestBarChart(tab)); + new TestBarChart(w); } diff --git a/test/graph/testBoxChart.cc b/test/graph/testBoxChart.cc index d9a34dc8..8fc517aa 100644 --- a/test/graph/testBoxChart.cc +++ b/test/graph/testBoxChart.cc @@ -7,7 +7,7 @@ using namespace grail; class TestBoxChart : public GraphStyle { public: - TestBoxChart(Tab* tab) : GraphStyle(tab, "TIMES", 20, 12) { + TestBoxChart(GLWin* w) : GraphStyle(w, "TIMES", 20, 12, "Box Chart") { MainCanvas* c = tab->getMainCanvas(); vector data = {150, 350, 222, 100, 300, // @@ -54,7 +54,7 @@ class TestBoxChart : public GraphStyle { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* tab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Test Bar Chart"); - tab->addMember(new TestBoxChart(tab)); + new TestBoxChart(w); } diff --git a/test/graph/testCandlestickChart.cc b/test/graph/testCandlestickChart.cc index 60471295..7309bdbd 100644 --- a/test/graph/testCandlestickChart.cc +++ b/test/graph/testCandlestickChart.cc @@ -7,7 +7,7 @@ using namespace grail; class TestCandlestickChart : public GraphStyle { public: - TestCandlestickChart(Tab* tab) : GraphStyle(tab, "TIMES", 20, 12) { + TestCandlestickChart(GLWin* w) : GraphStyle(w, "TIMES", 20, 12, "Candlestick Chart") { MainCanvas* c = tab->getMainCanvas(); vector data = { @@ -72,6 +72,6 @@ class TestCandlestickChart : public GraphStyle { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* tab) { - tab->addMember(new TestCandlestickChart(tab)); +void grailmain(int argc, char* argv[], GLWin* w) { + new TestCandlestickChart(w); } diff --git a/test/graph/testGapMinderWidget.cc b/test/graph/testGapMinderWidget.cc index d2a8b2c4..4054e7fa 100644 --- a/test/graph/testGapMinderWidget.cc +++ b/test/graph/testGapMinderWidget.cc @@ -15,7 +15,7 @@ class TestGapMinderWidget : public GraphStyle { GapMinderWidget* chart; public: - TestGapMinderWidget(Tab* tab) : GraphStyle(tab, "TIMES", 24, 12) { + TestGapMinderWidget(GLWin* w) : GraphStyle(w, "TIMES", 24, 12, "Gapninder graph") { MainCanvas* c = tab->getMainCanvas(); const Style* s = new Style("TIMES", 24, 1, 0, 0, 0, // black background (unused) @@ -42,7 +42,7 @@ class TestGapMinderWidget : public GraphStyle { void update() { chart->animate(10000, 2); } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* tab) { +void grailmain(int argc, char* argv[], GLWin* w) { w->setTitle("Test Gap Minder Widget"); - tab->addMember(new TestGapMinderWidget(tab)); + new TestGapMinderWidget(w); } diff --git a/test/graph/testLineGraph.cc b/test/graph/testLineGraph.cc index 366d3274..91ed960f 100644 --- a/test/graph/testLineGraph.cc +++ b/test/graph/testLineGraph.cc @@ -7,7 +7,7 @@ using namespace grail; class TestLineGraph : public GraphStyle { public: - TestLineGraph(Tab* tab) : GraphStyle(tab, "TIMES", 24, 12) { + TestLineGraph(GLWin* w) : GraphStyle(w, "TIMES", 24, 12,"Line Graph") { MainCanvas* c = tab->getMainCanvas(); vector times = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; @@ -65,6 +65,4 @@ class TestLineGraph : public GraphStyle { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* tab) { - tab->addMember(new TestLineGraph(tab)); -} +void grailmain(int argc, char* argv[], GLWin* w) { new TestLineGraph(w); } diff --git a/test/maps/testDrawBlockMap.cc b/test/maps/testDrawBlockMap.cc index 74912e64..6af17059 100644 --- a/test/maps/testDrawBlockMap.cc +++ b/test/maps/testDrawBlockMap.cc @@ -12,8 +12,8 @@ class TestDrawBlockMap : public Member { MapView2D* mv; public: - TestDrawBlockMap(Tab* tab, const char filename[]) - : Member(tab), // GLWin(0x000000, 0xCCCCCC, "Block Loader: Map Demo"), + TestDrawBlockMap(GLWin* w, const char filename[]) + : Member(w), // GLWin(0x000000, 0xCCCCCC, "Block Loader: Map Demo"), filename(filename), mv(nullptr) { MainCanvas* c = tab->getMainCanvas(); @@ -97,6 +97,6 @@ class TestDrawBlockMap : public Member { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { - new TestDrawBlockMap(defaultTab, "res/maps/uscounties.bml"); +void grailmain(int argc, char* argv[], GLWin* w) { + new TestDrawBlockMap(w, "res/maps/uscounties.bml"); } diff --git a/test/media/testAudio.cc b/test/media/testAudio.cc index 7374084f..df07b84c 100644 --- a/test/media/testAudio.cc +++ b/test/media/testAudio.cc @@ -22,8 +22,7 @@ class TestAudioPlayer : public Member { } public: - TestAudioPlayer(Tab *tab) - : Member(tab, 0), startTime(0), a(nullptr), step(0) {} + TestAudioPlayer(GLWin *w) : Member(w, 0), startTime(0), a(nullptr), step(0) {} // required to ensure that the memory of the audio player is freed ~TestAudioPlayer() { delete a; } @@ -136,6 +135,4 @@ class TestAudioPlayer : public Member { } }; -void grailmain(int argc, char *argv[], GLWin *w, Tab *defaultTab) { - new TestAudioPlayer(defaultTab); -} +void grailmain(int argc, char *argv[], GLWin *w) { new TestAudioPlayer(w); } diff --git a/test/media/testSingleAudio.cc b/test/media/testSingleAudio.cc index b7726f09..b5207f53 100644 --- a/test/media/testSingleAudio.cc +++ b/test/media/testSingleAudio.cc @@ -4,7 +4,7 @@ class TestSingleAudio : public Member { public: AudioPlayer *a; - TestSingleAudio(Tab *tab) : Member(tab) { + TestSingleAudio(GLWin *w) : Member(w) { a = new AudioPlayer(); a->setCurrentContext("default"); @@ -14,6 +14,4 @@ class TestSingleAudio : public Member { } }; -void grailmain(int argc, char *argv[], GLWin *w, Tab *defaultTab) { - defaultTab->addMember(new TestSingleAudio(defaultTab)); -} \ No newline at end of file +void grailmain(int argc, char *argv[], GLWin *w) { new TestSingleAudio(w); } \ No newline at end of file diff --git a/test/media/testVideo.cc b/test/media/testVideo.cc index 1bf79fc4..65d0c6bc 100644 --- a/test/media/testVideo.cc +++ b/test/media/testVideo.cc @@ -6,7 +6,7 @@ using namespace grail; class TestVideoPlayer : public Member { public: - TestVideoPlayer(Tab* tab) : Member(tab, 0) { + TestVideoPlayer(GLWin* w) : Member(w, 0) { VideoPlayer* v = c->addLayer(new VideoPlayer(c, 100, 100, 500, 500)); // playing a link from youtube (and maybe other places idk) requires you to @@ -21,6 +21,4 @@ class TestVideoPlayer : public Member { } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { - new TestVideoPlayer(defaultTab); -} +void grailmain(int argc, char* argv[], GLWin* w) { new TestVideoPlayer(w); } diff --git a/test/xdl/testXDLButton.cc b/test/xdl/testXDLButton.cc index 34451240..c596aa85 100644 --- a/test/xdl/testXDLButton.cc +++ b/test/xdl/testXDLButton.cc @@ -9,13 +9,11 @@ class NetworkedButton : public Member { ButtonWidget button; public: - NetworkedButton(Tab* tab) - : Member(tab), button(c, 0, 0, 100, 100, "", "click!") { + NetworkedButton(GLWin* w) + : Member(w), button(c, w->getDefaultStyle(),0, 0, 100, 100, "", "click!") { button.setAction( bind(&GLWin::goToLink, tab->getParentWin(), "127.0.0.1", 8060, 0)); } }; -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { - defaultTab->addMember(new NetworkedButton(defaultTab)); -} \ No newline at end of file +void grailmain(int argc, char* argv[], GLWin* w) { new NetworkedButton(w); } \ No newline at end of file diff --git a/test/xp/BarChart.hh b/test/xp/BarChart.hh new file mode 100644 index 00000000..ebdf8ac4 --- /dev/null +++ b/test/xp/BarChart.hh @@ -0,0 +1,56 @@ +#pragma once +#include "opengl/BarChartWidget.hh" + +using namespace std; + +class BarChart : public GraphStyle { + public: + BarChart(GLWin* w) : GraphStyle(w->addTab(), "TIMES", 20, 12, "Bar") { + MainCanvas* c = tab->getMainCanvas(); + vector values = {4, 6, 8, 10, 12, 14}; + vector logValues = {4, 8, 16, 32, 64, 128}; + + vector names = {"red", "orange", "yellow", + "green", "blue", "purple"}; + + vector colors = {grail::red, grail::orange, grail::yellow, + grail::green, grail::blue, grail::purple}; + + vector outline{grail::green, grail::blue, grail::purple}; + + BarChartWidget bcw(c, 100, 300, 850, 400, GraphWidget::AxisType::TEXT, + GraphWidget::AxisType::LINEAR, this); + + // create x axis (categories) + bcw.setNames(names); + // bcw.createXAxis(GraphWidget::AxisType::TEXT); + bcw.xAxis->setTitle("Colors"); + + // y axis stuff + // bcw.createYAxis(GraphWidget::AxisType::LINEAR); + bcw.setValues(values); + + // setting general things for the graph + // the axis text styles must be set before + // creating the axes + bcw.setGraphTitle("Bar Chart"); + // bcw.setStyle(this); + + // bar chart widget specific bits + // bcw.setBarColors(colors); + // bcw.setBarOutlineColors(outline); + // linear + bcw.yAxis->setBounds(0, 60); + bcw.yAxis->setTickInterval(2); + bcw.yAxis->setTitle("y axis"); + + // logarithmic + // bcw.createYAxis(GraphWidget::AxisType::LOGARITHMIC); + // bcw.yAxis->setBounds(1, 256); + // bcw.yAxis->setTickInterval(2); + // bcw.yAxis->setTickFormat(4, 1); + // bcw.setValues(logValues); + + bcw.init(); + } +}; \ No newline at end of file diff --git a/test/xp/BoxChart.hh b/test/xp/BoxChart.hh new file mode 100644 index 00000000..7f179910 --- /dev/null +++ b/test/xp/BoxChart.hh @@ -0,0 +1,49 @@ +#pragma once +#include "opengl/BoxChartWidget.hh" + +using namespace std; + +class BoxChart : public GraphStyle { + public: + BoxChart(GLWin* w) : GraphStyle(w->addTab(), "TIMES", 20, 12, "Box") { + MainCanvas* c = tab->getMainCanvas(); + + vector data = {150, 350, 222, 100, 300, // + 130, 300, 250, 190, 170, // + 100, 50, 20, 150, 200, // + 330, 200, 270, 180, 300, // + 49, 247, 325, 114, 89}; + + vector names = {"red", "orange", "yellow", "green", "blue"}; + + BoxChartWidget bcw(c, 100, 300, 850, 200, GraphWidget::AxisType::TEXT, + GraphWidget::AxisType::LINEAR, this); + + // setting general things for the graph + // the axis text styles must be set before + // creating the axes + bcw.setGraphTitle("Box Chart"); + + // create x axis (categories) + bcw.setNames(names); + + // set releavant x axis parameters + // if you try to set something not applicable to a text axis (as that's what + // the x axis always will be), the compiler will yell at you + bcw.xAxis->setTitle("Colors"); + + // y axis stuff + bcw.setData(data); + bcw.yAxis->setTitle("y axis"); + // linear + bcw.yAxis->setBounds(0, 500); + bcw.yAxis->setTickInterval(75); + + // set y axis parameters + // bar chart widget specific bits + bcw.setBoxWidth(45); + bcw.setPointsPerBox(5); + + bcw.init(); + } +}; \ No newline at end of file diff --git a/test/xp/CMakeLists.txt b/test/xp/CMakeLists.txt index 1d84e74a..65a54386 100644 --- a/test/xp/CMakeLists.txt +++ b/test/xp/CMakeLists.txt @@ -1,4 +1,8 @@ # add_grail_executable([BINNAME ] SRC LIBS ) add_grail_executable(SRC testfmt.cc LIBS grail) -add_grail_executable(SRC testMultiTab.cc LIBS grail) \ No newline at end of file +add_grail_executable(SRC testMultiTab.cc LIBS grail) +add_grail_executable(SRC test2Tabs.cc LIBS grail) +add_grail_executable(SRC testGraphTabs.cc LIBS grail) +add_grail_executable(SRC testAutoGraphTabs.cc LIBS grail) +add_grail_executable(SRC testMenu.cc LIBS grail) \ No newline at end of file diff --git a/test/xp/CandlestickChart.hh b/test/xp/CandlestickChart.hh new file mode 100644 index 00000000..66d60b0a --- /dev/null +++ b/test/xp/CandlestickChart.hh @@ -0,0 +1,71 @@ +#pragma once +#include "opengl/CandlestickChartWidget.hh" + +using namespace std; + +class CandlestickChart : public GraphStyle { + public: + CandlestickChart(GLWin* w) : GraphStyle(w, "TIMES", 20, 12, "CStick") { + MainCanvas* c = tab->getMainCanvas(); + + vector data = { + 153.25, 154.16, 152.99, 153.68, 153.34, 153.73, 152.15, 152.73, 152.66, + 153.58, 151.46, 153.57, 153.71, 153.9, 152.17, 153.26, 153.46, 154.53, + 153.36, 153.92, 153.08, 153.31, 151.91, 152.93, 153.63, 154.88, 153.5, + 154.83, 154.41, 154.93, 154.01, 154.74, 155.25, 156.17, 154.93, 155.28, + 155.5, 157.43, 154.54, 155.34, 155.41, 156.42, 155.19, 155.99, 155.79, + 156.81, 155.17, 155.44, 156.17, 156.72, 155.85, 156.43, 157.33, 159.43, + 157.09, 159.31, 159.21, 160.29, 158.66, 159.9, 159.85, 160.13, 159.03, + 159.19, 156.19, 156.52, 154.46, 155.42, 156.05, 157.18, 155.4, 155.69, + 156.33, 157.13, 154.94, 155.61, 155.73, 156.86, 155.64, 156.54, 156.35, + 156.99, 154.71, 155.85, 156.67, 157.26, 156.22, 156.85, 158.72, 163.01, + 158.13, 162.47, 163.3, 167.47, 163.13, 166.12, 167.3, 169.04, 166.34, + 168.43, 169.26, 169.33, 165.02, 166.29, 167.04, 167.9, 164.69, 167.51, + 173.38, 173.64, 170.51, 171.88, 171.75, 174.36, 171.1, 173.63, 173.29, + 174.51, 173.29, 174.18, 174.03, 175.61, 173.71, 175.61, 174.48, 175.46, + 172.52, 175.25, 175.11, 175.38, 174.27, 174.67}; + vector names = {"one", "two", "seven", "three"}; + CandlestickChartWidget ccw(c, 100, 300, 850, 400, + GraphWidget::AxisType::LINEAR, + GraphWidget::AxisType::LINEAR, this); + + // setting general things for the graph + // the axis text styles must be set before + // creating the axes + ccw.setGraphTitle("Candlestick Chart"); + + // bar chart widget specific bits + // ccw.setBoxWidth(5); + // ccw.setBoxColors(boxColors); + // ccw.setBoxOutlineColors(outlineColors); + + // create x axis (categories) + // ccw.setNames(names); + + // set relevant x axis parameters + // if you try to set something not applicable to a text axis (as that's what + // the x axis always will be), the compiler will yell at you + ccw.xAxis->setTitle("Date"); + // ccw.xAxis->setTickDrawSize(7); + // ccw.xAxis->setAxisColor(grail::green); + // ccw.xAxis->setTickColor(grail::purple); + + // y axis stuff + ccw.setData(data); + + // set y axis parameters + // ccw.yAxis->setIsVert(true); + + // linear + ccw.yAxis->setBounds(140, 180); + ccw.yAxis->setTickInterval(2); + + // ccw.yAxis->setTickDrawSize(10); + // ccw.yAxis->setShowTicks(true); + ccw.yAxis->setTitle("Price"); + // ccw.yAxis->setAxisColor(grail::yellow); + // ccw.yAxis->setTickColor(grail::red); + + ccw.init(); + } +}; \ No newline at end of file diff --git a/test/xp/LineGraph.hh b/test/xp/LineGraph.hh new file mode 100644 index 00000000..b9eb3485 --- /dev/null +++ b/test/xp/LineGraph.hh @@ -0,0 +1,44 @@ +#pragma once +#include "opengl/LineGraphWidget.hh" + +using namespace std; + +class LineGraph : public GraphStyle { + public: + LineGraph(GLWin* w) : GraphStyle(w->addTab(), "TIMES", 24, 12, "Line") { + MainCanvas* c = tab->getMainCanvas(); + + vector times = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + vector values = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20}; + vector logValues = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}; + + LineGraphWidget lgw(c, 250, 300, 500, 300, GraphWidget::AxisType::LINEAR, + GraphWidget::AxisType::LOGARITHMIC, this); + + // Graph Superclass settings + lgw.setGraphTitle("Line Graph"); + + // LineGraphWidget specific settings + lgw.setPointFormat('t', 5, grail::red); + + // x axis stuff + lgw.setXPoints(times); + + // set x axis parameters + lgw.xAxis->setBounds(times.front(), times.back()); + lgw.xAxis->setTickInterval(2); + lgw.xAxis->setTitle("x axis"); + lgw.xAxis->setTickFormat(3, 1); + + // y axis stuff + lgw.setYPoints(logValues); + + // set y axis parameters + lgw.yAxis->setBounds(logValues.front(), logValues.back()); + lgw.yAxis->setTickInterval(2); + lgw.yAxis->setTickFormat(4, 1); + lgw.yAxis->setTitle("y axis"); + + lgw.init(); + } +}; \ No newline at end of file diff --git a/test/xp/test2Tabs.cc b/test/xp/test2Tabs.cc new file mode 100644 index 00000000..a215b2a6 --- /dev/null +++ b/test/xp/test2Tabs.cc @@ -0,0 +1,46 @@ +#include "fmt/core.h" +#include "opengl/GrailGUI.hh" +#include "opengl/NavigationBar.hh" +#include "util/Ex.hh" + +using namespace std; +using namespace grail; + +class Square : public Member { + public: + Square(GLWin* w) : Member(w, 0, 0) { + StyledMultiShape2D* gui = tab->getMainCanvas()->getGui(); + gui->fillRectangle(500, 600, 200, 200, red); + } +}; + +class Circle : public Member { + public: + Circle(GLWin* w) : Member(w, 0, 0) { + StyledMultiShape2D* gui = tab->getMainCanvas()->getGui(); + gui->fillCircle(600, 700, 100, 5, purple); + } +}; + +class MultiTab : public NavigationBar { + public: + MultiTab(GLWin* w); +}; + +MultiTab::MultiTab(GLWin* w) : NavigationBar(w, 0, 0, 250, 200, 20, true) { + ButtonWidget* square = addButton(250, 50, "Square", "tab 1"); + square->setAction([w]() { w->switchTab(0); }); + + ButtonWidget* circle = addButton(250, 50, "Circle", "tab 2"); + circle->setAction([w]() { w->switchTab(1); }); + + ButtonWidget* next = addButton(250, 50, "Next", "next tab"); + next->setAction([w]() { w->nextTab(); }); +} + +void grailmain(int argc, char* argv[], GLWin* w) { + w->setTitle("Test Tabs"); + new Square(w); + MultiTab* m = new MultiTab(w); + new Circle(w); +} \ No newline at end of file diff --git a/test/xp/testAutoGraphTabs.cc b/test/xp/testAutoGraphTabs.cc new file mode 100644 index 00000000..3fbea410 --- /dev/null +++ b/test/xp/testAutoGraphTabs.cc @@ -0,0 +1,19 @@ +#include "BarChart.hh" +#include "BoxChart.hh" +#include "CandlestickChart.hh" +#include "LineGraph.hh" +#include "opengl/AutoNavBar.hh" +#include "opengl/GrailGUI.hh" + +using namespace std; +using namespace grail; + +void grailmain(int argc, char* argv[], GLWin* w) { + AutoNavBar* bar = new AutoNavBar(w, 0, 0, 10, 5, 5, false, true); + bar->setButtonStyle(FontFace::get("TIMES", 28, FontFace::BOLD), grail::black, + grail::yellow, 2); + new CandlestickChart(w); + new LineGraph(w); + new BoxChart(w); + new BarChart(w); +} \ No newline at end of file diff --git a/test/xp/testGraphTabs.cc b/test/xp/testGraphTabs.cc new file mode 100644 index 00000000..682cac47 --- /dev/null +++ b/test/xp/testGraphTabs.cc @@ -0,0 +1,42 @@ +#include "BarChart.hh" +#include "BoxChart.hh" +#include "CandlestickChart.hh" +#include "LineGraph.hh" +#include "opengl/GrailGUI.hh" +#include "opengl/NavigationBar.hh" + +using namespace std; +using namespace grail; + +class ChartNavBar : public NavigationBar { + public: + ChartNavBar(GLWin* w); +}; + +ChartNavBar::ChartNavBar(GLWin* w) : NavigationBar(w, 0, 0, 400, 50, 10) { + setButtonStyle((Font*)FontFace::get("TIMES", 28, FontFace::BOLD), + grail::black, grail::yellow, 2); + + ButtonWidget* bar = addButton("Bar", "tab 1"); + bar->setAction([w]() { w->switchTab(3); }); + + ButtonWidget* box = addButton("Box", "tab 2"); + box->setAction([w]() { w->switchTab(2); }); + + ButtonWidget* line = addButton("Line", "tab 3"); + line->setAction([w]() { w->switchTab(1); }); + + ButtonWidget* cstick = addButton("CStick", "tab 4"); + cstick->setAction([w]() { w->switchTab(0); }); + + fitBarDimensions(5, 5); + drawBarBox(); +} + +void grailmain(int argc, char* argv[], GLWin* w) { + new ChartNavBar(w); + new CandlestickChart(w); + new LineGraph(w); + new BoxChart(w); + new BarChart(w); +} \ No newline at end of file diff --git a/test/xp/testMenu.cc b/test/xp/testMenu.cc new file mode 100644 index 00000000..b4a52593 --- /dev/null +++ b/test/xp/testMenu.cc @@ -0,0 +1,31 @@ +#include "opengl/DropDownMenu.hh" +#include "opengl/GrailGUI.hh" + +using namespace std; +using namespace grail; + +class Square : public Member { + public: + Square(GLWin* w) : Member(w, "Square", 0, 0) { + StyledMultiShape2D* gui = tab->getMainCanvas()->getGui(); + gui->fillRectangle(500, 600, 200, 200, red); + } +}; + +class Circle : public Member { + public: + Circle(GLWin* w) : Member(w, "Circle", 0, 0) { + StyledMultiShape2D* gui = tab->getMainCanvas()->getGui(); + gui->fillCircle(600, 700, 100, 5, purple); + } +}; + +void grailmain(int argc, char* argv[], GLWin* w) { + w->setTitle("Test Tabs"); + Style* s = new Style(FontFace::get("TIMES", 28, FontFace::BOLD), grail::black, + grail::lightblue, 2); + DropDownMenu* menu = new DropDownMenu(w, 0, 0, "Tabs", 5, 0, 0, s); + new Square(w); + new Circle(w); + menu->closeMenu(); +} \ No newline at end of file diff --git a/test/xp/testMultiTab.cc b/test/xp/testMultiTab.cc index b6cfa402..d40807f7 100644 --- a/test/xp/testMultiTab.cc +++ b/test/xp/testMultiTab.cc @@ -1,40 +1,25 @@ #include -#include "opengl/ButtonWidget.hh" #include "opengl/GrailGUI.hh" #include "opengl/NavigationBar.hh" using namespace std; -class MultiTab : public Member { - private: - ButtonWidget prev, next, add; - GLWin* parentWin; - +class MultiTab : public NavigationBar { public: - void addTab(); - - MultiTab(Tab* tab); + MultiTab(GLWin* w); }; -void MultiTab::addTab() { - Tab* t = parentWin->addTab(); - t->addMember(this); - t->setUpdate(); -} - -MultiTab::MultiTab(Tab* tab) - : Member(tab), - prev(c, 0, 0, 200, 30, "previous", "previous tab"), - next(c, 0, 50, 200, 30, "next", "next tab"), - add(c, 0, 100, 200, 30, "+", "add tab") { - parentWin = tab->getParentWin(); - prev.setAction(bind(&GLWin::prevTab, parentWin)); - next.setAction(bind(&GLWin::nextTab, parentWin)); - add.setAction(bind(&MultiTab::addTab, this)); +MultiTab::MultiTab(GLWin* w) : NavigationBar(w, 0, 0, 200, 130, 20, true) { + ButtonWidget* prev = addButton(200, 30, "previous", "previous tab"); + prev->setAction(bind(&GLWin::prevTab, w)); + ButtonWidget* next = addButton(200, 30, "next", "next tab"); + next->setAction(bind(&GLWin::nextTab, w)); + ButtonWidget* add = addButton(200, 30, "+", "add tab"); + add->setAction(bind(&GLWin::addTab, w)); } -void grailmain(int argc, char* argv[], GLWin* w, Tab* defaultTab) { - new MultiTab(defaultTab); - new NavigationBar(defaultTab, 0, 500, 600, 50, 2); +void grailmain(int argc, char* argv[], GLWin* w) { + w->addTab(); + new MultiTab(w); }