diff --git a/Menu.cpp b/Menu.cpp index 0866a70..41b8b0f 100644 --- a/Menu.cpp +++ b/Menu.cpp @@ -1,5 +1,29 @@ #include "header-files/Menu.h" +Menu::Menu(EditModeMouseFunction& e, InsertModeMouseFunction& i) : editModeMouseFunction(e), insertModeMouseFunction(i) { + for (int i = 0; i < 20; i++) { + currentHover.push_back(false); + } +} + +Menu::~Menu() { + al_destroy_bitmap(divider); + al_destroy_bitmap(background); + al_destroy_font(font); + for (auto i : buttons) { + al_destroy_bitmap(i); + } + for (auto i : hoverButtons) { + al_destroy_bitmap(i); + } + for (auto i : colorButtons) { + al_destroy_bitmap(i); + } + for (auto i : colorHoverButtons) { + al_destroy_bitmap(i); + } +} + void Menu::initDivider(ALLEGRO_BITMAP* div) { divider = div; } @@ -69,27 +93,51 @@ void Menu::detectMouse(int px, int py) { if (py < 75 && py > 0 && px >= i*75 && px < (i+1)*75) { al_draw_bitmap(hoverButtons[i], i*75, 0, 0); al_draw_text(font, al_map_rgb(0, 0, 0), 3, 80, ALLEGRO_ALIGN_LEFT, hoverStrings[i]); + currentHover.at(i) = true; + } + else { + currentHover.at(i) = false; } } for (unsigned int i = 0; i < 4; i++) { if (py < 37 && py > 0 && px >= 10 * 75 + 37 * i && px < 10 * 75 + 37 * (i + 1)) { al_draw_bitmap(colorHoverButtons.at(i), 10 * 75 + 37 * i, 0, 0); al_draw_text(font, al_map_rgb(0, 0, 0), 3, 80, ALLEGRO_ALIGN_LEFT, hoverStrings[i+10]); + currentHover.at(i + 10) = true; + } + else { + currentHover.at(i + 10) = false; } } for (unsigned int i = 4; i < 8; i++) { if (py < 75 && py > 37 && px >= 10 * 75 + 37 * (i - 4) && px < 10 * 75 + 37 * (i - 4 + 1)) { al_draw_bitmap(colorHoverButtons.at(i), 10 * 75 + 37 * (i - 4), 38, 0); al_draw_text(font, al_map_rgb(0, 0, 0), 3, 80, ALLEGRO_ALIGN_LEFT, hoverStrings[i-4+14]); + currentHover.at(i + 10) = true; + } + else { + currentHover.at(i + 10) = false; } } if (py > 14 && py < 69 && px >= 900 && px < 950) { al_draw_bitmap(hoverButtons.at(10), 900, 14, 0); al_draw_text(font, al_map_rgb(0, 0, 0), 3, 80, ALLEGRO_ALIGN_LEFT, hoverStrings[18]); + currentHover.at(18) = true; + } + else { + currentHover.at(18) = false; } if (py > 14 && py < 69 && px >= 950 && px < 1000) { al_draw_bitmap(hoverButtons.at(11), 950, 14, 0); al_draw_text(font, al_map_rgb(0, 0, 0), 3, 80, ALLEGRO_ALIGN_LEFT, hoverStrings[19]); + currentHover.at(19) = true; + } + else { + currentHover.at(19) = false; } } + +bool Menu::checkOverButton(int x) { + return currentHover.at(x); +} diff --git a/README.md b/README.md index 55f7d31..b2e6f3d 100644 --- a/README.md +++ b/README.md @@ -56,10 +56,12 @@ at a later time. The file will be created if it does not exist. ### Future Features: * Documentation on shape scheme * Makefile for easier compilation -* Menu onscreen allowing users to change colors of shapes, changes modes, etc. +* Menu onscreen allowing users to change colors of shapes, changes modes, etc. *(in progress)* * Add support for users to add onscreen text * Allowing users to specify which file to open in the application instead of only via command line * Detailed documentation on design patterns used * Detailed description on how to install Allegro +### Copyright Info + © Tyler Hinrichs 2022 \ No newline at end of file diff --git a/header-files/ECGraphicViewImp.h b/header-files/ECGraphicViewImp.h index e0cfce4..05bdd9d 100644 --- a/header-files/ECGraphicViewImp.h +++ b/header-files/ECGraphicViewImp.h @@ -58,7 +58,9 @@ enum ECGVEventType ECGV_EV_KEY_DOWN_F = 25, ECGV_EV_KEY_UP_F = 26, ECGV_EV_KEY_DOWN_CTRL = 27, - ECGV_EV_KEY_UP_CTRL = 28 + ECGV_EV_KEY_UP_CTRL = 28, + ECGV_EV_KEY_DOWN_S = 29, + ECGV_EV_KEY_DOWN_H = 30 }; //*********************************************************** @@ -140,6 +142,12 @@ class ECGraphicViewImp : public ECObserverSubject void DrawFilledCircle(int xcenter, int ycenter, double radius, ECGVColor color = ECGV_BLACK); void DrawEllipse(int xcenter, int ycenter, double radiusx, double radiusy, int thickness = 3, ECGVColor color = ECGV_BLACK); void DrawFilledEllipse(int xcenter, int ycenter, double radiusx, double radiusy, ECGVColor color = ECGV_BLACK); + // cursor setting + void insertCursor(); + void defaultCursor(); + + // Access view + ALLEGRO_DISPLAY* getDisplay() { return display; } private: // Internal functions diff --git a/header-files/ECRealObserver.h b/header-files/ECRealObserver.h index 79eaf2c..114f397 100644 --- a/header-files/ECRealObserver.h +++ b/header-files/ECRealObserver.h @@ -15,15 +15,16 @@ class ECAbstractMouseFunction; // Spacebar observer // used to change mode -class ECSpaceObserver : public ECObserver +class ECModeObserver : public ECObserver { public: - ECSpaceObserver(ECGraphicViewImp& view, Controller& ctrl) : view(view), ctrl(ctrl) {} - virtual ~ECSpaceObserver() {} + ECModeObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} + virtual ~ECModeObserver() {} virtual void Update() override; private: ECGraphicViewImp& view; Controller& ctrl; + Menu& menu; }; // Draw observer @@ -31,31 +32,31 @@ class ECSpaceObserver : public ECObserver class ECDrawObserver : public ECObserver { public: - ECDrawObserver(ECGraphicViewImp& view, Controller& ctrl) : view(view), ctrl(ctrl) {} + ECDrawObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} virtual ~ECDrawObserver() {} virtual void Update() override; - void attachMenu(Menu* m) { menu = m; } private: ECGraphicViewImp& view; Controller& ctrl; - Menu* menu; + Menu& menu; }; -// D key observer +// Delete observer // deletes selected shape in edit mode -class ECDObserver : public ECObserver +class ECDelObserver : public ECObserver { public: - ECDObserver(ECGraphicViewImp& view, Controller& ctrl) : view(view), ctrl(ctrl) {} - virtual ~ECDObserver() {} - virtual void Update(); + ECDelObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} + virtual ~ECDelObserver() {} + virtual void Update() override; private: ECGraphicViewImp& view; Controller& ctrl; + Menu& menu; }; // Mouse Observer -// various functionality when mouse is pressed down/up in both edit and insert mode +// various functionality when mouse is pressed down/up in both edit and insert mode (doesn't include menu clicking functionality) class ECMouseObserver : public ECObserver { public: @@ -74,39 +75,41 @@ class ECMouseObserver : public ECObserver class ECUndoRedoObserver : public ECObserver { public: - ECUndoRedoObserver(ECGraphicViewImp& view, Controller& ctrl) : view(view), ctrl(ctrl) {} + ECUndoRedoObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} virtual ~ECUndoRedoObserver() {} virtual void Update(); private: ECGraphicViewImp& view; Controller& ctrl; + Menu& menu; }; -// G Key Observer -// Toggles rectangle and ellipse insertion when in insert mode +// Group Observer // Groups/ungroups when in edit mode -class ECGObserver : public ECObserver +class ECGroupObserver : public ECObserver { public: - ECGObserver(ECGraphicViewImp& view, Controller& ctrl) : view(view), ctrl(ctrl) {} - virtual ~ECGObserver() {} + ECGroupObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} + virtual ~ECGroupObserver() {} virtual void Update(); private: ECGraphicViewImp& view; Controller& ctrl; + Menu& menu; }; -// F Key Observer -// Toggles filled and non-filled mode -class ECFObserver : public ECObserver +// Type Insert Observer +// Determines which shape to insert +class ECTypeInsertObserver : public ECObserver { public: - ECFObserver(ECGraphicViewImp& view, Controller& ctrl) : view(view), ctrl(ctrl) {} - virtual ~ECFObserver() {} + ECTypeInsertObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} + virtual ~ECTypeInsertObserver() {} virtual void Update(); private: ECGraphicViewImp& view; Controller& ctrl; + Menu& menu; }; // CTRL Key Observer @@ -122,6 +125,48 @@ class ECCtrlObserver : public ECObserver Controller& ctrl; }; +// Color Observer +// Allows user to change color with buttons in menu +class ECColorObserver : public ECObserver +{ +public: + ECColorObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} + virtual ~ECColorObserver() {} + virtual void Update(); +private: + ECGraphicViewImp& view; + Controller& ctrl; + Menu& menu; +}; + +// Save Observer +// Allows user to save via the keyboard or menu +class ECSaveObserver : public ECObserver +{ +public: + ECSaveObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} + virtual ~ECSaveObserver() {} + virtual void Update(); +private: + ECGraphicViewImp& view; + Controller& ctrl; + Menu& menu; +}; + +// Help Observer +// Allows user to save via the keyboard or menu +class ECHelpObserver : public ECObserver +{ +public: + ECHelpObserver(ECGraphicViewImp& view, Controller& ctrl, Menu& m) : view(view), ctrl(ctrl), menu(m) {} + virtual ~ECHelpObserver() {} + virtual void Update(); +private: + ECGraphicViewImp& view; + Controller& ctrl; + Menu& menu; +}; + // Arrow Key Observers // When pressed, they move all selected shapes 10 by the direction specified by the key pressed class ECGenericArrowObserver : public ECObserver diff --git a/header-files/Menu.h b/header-files/Menu.h index a968719..2337515 100644 --- a/header-files/Menu.h +++ b/header-files/Menu.h @@ -16,11 +16,10 @@ using namespace std; class Menu { public: - Menu(EditModeMouseFunction& e, InsertModeMouseFunction& i): editModeMouseFunction(e), insertModeMouseFunction(i) {} - ~Menu() {} // TODO: destroy all bitmaps + Menu(EditModeMouseFunction& e, InsertModeMouseFunction& i); + ~Menu(); // TODO: destroy all bitmaps void initDivider(ALLEGRO_BITMAP* div); void initBackground(ALLEGRO_BITMAP* bg); - void initButtons(vector bts); void initHoverButtons(vector bts); void initColorButtons(vector bts); @@ -28,6 +27,7 @@ class Menu { void initFont(ALLEGRO_FONT* f); void timer(int mode); // draws all menu buttons and take care of trace shapes void detectMouse(int px, int py); + bool checkOverButton(int x); private: ALLEGRO_BITMAP* divider; ALLEGRO_BITMAP* background; @@ -60,6 +60,7 @@ class Menu { }; EditModeMouseFunction& editModeMouseFunction; InsertModeMouseFunction& insertModeMouseFunction; + vector currentHover; // keeps track of what button is currently being hovered over }; #endif diff --git a/header-files/ShapesModel.h b/header-files/ShapesModel.h index f9a6cd0..2bf081f 100644 --- a/header-files/ShapesModel.h +++ b/header-files/ShapesModel.h @@ -5,13 +5,15 @@ #include "Command.h" #include #include +#include +#include using namespace std; class ECCommandHistory; // necessary forward declaration class ShapesModel { public: - ShapesModel() {} + ShapesModel(string f): color(ECGV_BLACK), filename(f) {} vector getListShapes() { return listShapes; } void addShape(Shape* x) { listShapes.push_back(x); } void removeShape(Shape* x); @@ -26,11 +28,20 @@ class ShapesModel { void select(int px, int py, bool ctrlIsAsserted); vector getSelected(); // return currently selected shape void removeSelected(); // clears selected vector; deselects any shape that is selected + + // color ECGVColor parseColor(int x); + ECGVColor getColor(); // retrieves current color + void setColor(int x); // sets current color + + // saving + void save(); private: vector listShapes; vector selected; + ECGVColor color; + string filename; }; class Controller { @@ -68,13 +79,15 @@ class Controller { void deleteShape(); // delete selected shape void moveShape(int translateX, int translateY); // move shape to new position based on translation - // G key pressed + // G key pressed (G can be "pressed" from the menu) bool isGAsserted() { return gIsAsserted; } void pressGKey() { gIsAsserted = !gIsAsserted; } + void setGKey(bool x) { gIsAsserted = x; } // F key pressed bool isFAsserted() { return fIsAsserted; } void pressFKey() { fIsAsserted = !fIsAsserted; } + void setFKey(bool x) { fIsAsserted = x; } // Reset F and G assertions to false when switching modes void resetFandGAssertions(); @@ -89,13 +102,20 @@ class Controller { void pressLeftArrow(); void pressRightArrow(); - // G key in edit mode - void pressGKeyEditMode(); + // Group/Ungroup + void GroupShapes(); + void removeSelected() { model->removeSelected(); } // undo/redo operations void Undo(); void Redo(); + // color + void setColor(int x); + + // save + void save() { model->save(); } + private: ShapesModel* model; // reference to model ECCommandHistory* history; // saves history of all commands so far diff --git a/source-files/Command.cpp b/source-files/Command.cpp index 73b0d9e..78bbfd2 100644 --- a/source-files/Command.cpp +++ b/source-files/Command.cpp @@ -3,10 +3,10 @@ // insert command InsertShape :: InsertShape(int x1, int y1, int x2, int y2, ShapesModel* model, int type) : ECCommand(model) { // inserts a Rectangle by default, if type is asserted, inserts an Ellipse - if (type == 0) s = new Rectangle(x1, y1, x2, y2); - else if (type == 1) s = new Ellipse(x1, y1, x2, y2); - else if (type == 2) s = new FilledRectangle(x1, y1, x2, y2); - else if (type == 3) s = new FilledEllipse(x1, y1, x2, y2); + if (type == 0) s = new Rectangle(x1, y1, x2, y2, model->getColor()); + else if (type == 1) s = new Ellipse(x1, y1, x2, y2, model->getColor()); + else if (type == 2) s = new FilledRectangle(x1, y1, x2, y2, model->getColor()); + else if (type == 3) s = new FilledEllipse(x1, y1, x2, y2, model->getColor()); } void InsertShape::Execute() { diff --git a/source-files/ECGraphicViewImp.cpp b/source-files/ECGraphicViewImp.cpp index 0641fd9..d2015ec 100644 --- a/source-files/ECGraphicViewImp.cpp +++ b/source-files/ECGraphicViewImp.cpp @@ -228,7 +228,12 @@ ECGVEventType ECGraphicViewImp::WaitForEvent() case ALLEGRO_KEY_RCTRL: return ECGV_EV_KEY_DOWN_CTRL; + + case ALLEGRO_KEY_S: + return ECGV_EV_KEY_DOWN_S; + case ALLEGRO_KEY_H: + return ECGV_EV_KEY_DOWN_H; } } else if (ev.type == ALLEGRO_EVENT_KEY_UP) { @@ -335,3 +340,11 @@ void ECGraphicViewImp::DrawFilledEllipse(int xcenter, int ycenter, double radius { al_draw_filled_ellipse(xcenter, ycenter, radiusx, radiusy, arrayAllegroColors[color]); } + +void ECGraphicViewImp::defaultCursor() { + al_set_system_mouse_cursor(display, ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT); +} + +void ECGraphicViewImp::insertCursor() { + al_set_system_mouse_cursor(display, ALLEGRO_SYSTEM_MOUSE_CURSOR_PRECISION); +} diff --git a/source-files/ECRealObserver.cpp b/source-files/ECRealObserver.cpp index 0c301c4..a38ae62 100644 --- a/source-files/ECRealObserver.cpp +++ b/source-files/ECRealObserver.cpp @@ -1,11 +1,17 @@ #include "../header-files/ECRealObserver.h" +#include -// ECSpaceObserver -void ECSpaceObserver :: Update() { - if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_SPACE) { +// ECModeObserver +void ECModeObserver :: Update() { + // using spacebar to switch modes + if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_SPACE || + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(0) && ctrl.getMode() == 1 || // switching to edit with buttons + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(1) && ctrl.getMode() == 0) { // switching to insert with buttons ctrl.changeMode(); + if (ctrl.getMode() == 0) view.defaultCursor(); + if (ctrl.getMode() == 1) view.insertCursor(); ctrl.setMouseDownThisMode(0); - ctrl.resetFandGAssertions(); // changes F and G asserted to false when switching modes + //ctrl.resetFandGAssertions(); // changes F and G asserted to false when switching modes view.SetRedraw(true); // needed for color change of selected becoming unselected } } @@ -17,17 +23,17 @@ void ECDrawObserver :: Update() { x->Draw(view); view.SetRedraw(true); } - menu->timer(ctrl.getMode()); // draw menu buttons + menu.timer(ctrl.getMode()); // draw menu buttons int x, y; view.GetCursorPosition(x, y); - //cout << "(" << x << "," << y << ")" << endl; - menu->detectMouse(x, y); + menu.detectMouse(x, y); } } -// ECDObserver -void ECDObserver :: Update() { - if (ctrl.getMode() == 0 && view.GetCurrEvent() == ECGV_EV_KEY_DOWN_D) { +// ECDelObserver +void ECDelObserver :: Update() { + if (ctrl.getMode() == 0 && view.GetCurrEvent() == ECGV_EV_KEY_DOWN_D || + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(4)) { ctrl.deleteShape(); // deletes selected shape if in edit mode view.SetRedraw(true); } @@ -42,37 +48,60 @@ void ECMouseObserver::Update() { if (view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN) { mouseFunction.mouseDown(); } - /*if (view.GetCurrEvent() == ECGV_EV_TIMER) { - mouseFunction.timer(); - }*/ + // timer functionality moved to menu } } // ECUndoRedoObserver void ECUndoRedoObserver :: Update() { - if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_Z) { + if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_Z || + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(2)) { ctrl.Undo(); } - if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_Y) { + if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_Y || + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(3)) { ctrl.Redo(); } view.SetRedraw(true); // correct drawing for last undo } -// ECGObserver -void ECGObserver::Update() { - if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_G && ctrl.getMode() == 1) { - ctrl.pressGKey(); - } - else if (view.GetCurrEvent() == ECGV_EV_KEY_UP_G && ctrl.getMode() == 0) { - ctrl.pressGKeyEditMode(); +// ECGroupObserver +void ECGroupObserver::Update() { + // must be in edit mode, then check whether G is pressed or pressing the group button in menu + if (ctrl.getMode() == 0 && + view.GetCurrEvent() == ECGV_EV_KEY_DOWN_G || + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(5)) { + ctrl.GroupShapes(); + ctrl.removeSelected(); } } -// ECFObserver -void ECFObserver::Update() { - if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_F) { - ctrl.pressFKey(); +void ECTypeInsertObserver::Update() { + if (ctrl.getMode() == 1) { + if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_G) { + ctrl.pressGKey(); + } + else if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_F) { + ctrl.pressFKey(); + } + else if (view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN) { + if (menu.checkOverButton(6)) { + ctrl.setGKey(false); + ctrl.setFKey(false); + } + if (menu.checkOverButton(7)) { + ctrl.setGKey(true); + ctrl.setFKey(false); + } + if (menu.checkOverButton(8)) { + ctrl.setGKey(false); + ctrl.setFKey(true); + } + if (menu.checkOverButton(9)) { + ctrl.setGKey(true); + ctrl.setFKey(true); + } + } } } @@ -83,6 +112,50 @@ void ECCtrlObserver::Update() { } } +void ECColorObserver::Update() { + if (ctrl.getMode() == 1 && view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN) { + for (int i = 0; i < 8; i++) { + if (menu.checkOverButton(i+10)) { + ctrl.setColor(i); + } + } + } +} + +void ECSaveObserver::Update() { + if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_S || + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(18)) { + ctrl.save(); + } +} + +void ECHelpObserver::Update() { + if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_H || + view.GetCurrEvent() == ECGV_EV_MOUSE_BUTTON_DOWN && menu.checkOverButton(19)) { + al_show_native_message_box(view.getDisplay(), "Help", "Graphical Editor Help Information", + "Use the mouse to draw, select, and move shapes.\n" + "Hover over a button in the menu at the top of the screen to see what it does.\n\n" + "The keyboard can also be used for menu operations.\n" + "Press the spacebar to switch modes (edit and insert).\n" + "Press S to save.\n" + "Press H to open the Help Dialog (this message).\n" + "Press Z to undo an action.\n" + "Press Y to redo an action.\n\n" + "Insert Mode Only:\n" + "Press F to toggle filled and unfilled shapes.\n" + "Press G to toggle inserting a rectangle and ellipse.\n\n" + "Edit Mode Only:\n" + "Press D to delete a shape.\n" + "Press G to group multiple shapes or ungroup a singular grouped shape.\n" + "Hold down CTRL to select and move multiple shapes.\n" + "Use arrow keys to move shapes (can also use mouse to move).\n\n" + "For more information, please visit github.com/tylernh10/graphical-editor or refer to the README.md for this repository.\n\n" + "Thanks for checking out this project! :)" + , + NULL, ALLEGRO_MESSAGEBOX_QUESTION); + } +} + // ECUpArrowObserver void ECUpArrowObserver::Update() { if (view.GetCurrEvent() == ECGV_EV_KEY_DOWN_UP) { diff --git a/source-files/MouseFunction.cpp b/source-files/MouseFunction.cpp index 777daca..cf895ba 100644 --- a/source-files/MouseFunction.cpp +++ b/source-files/MouseFunction.cpp @@ -11,7 +11,6 @@ void ECAbstractMouseFunction::saveCursorPosition() { // EditModeMouseFunction void EditModeMouseFunction::mouseDown() { - // > 110 ensures that menu area is off limits if (!ctrl.getMouseDown()) { ctrl.setMouseDown(); ctrl.setMouseDownThisMode(1); diff --git a/source-files/ShapesModel.cpp b/source-files/ShapesModel.cpp index a959ccc..02877ad 100644 --- a/source-files/ShapesModel.cpp +++ b/source-files/ShapesModel.cpp @@ -55,7 +55,6 @@ void Controller::changeMode() { void Controller::select(int px, int py) { if (py <= 110) { - //cout << "selected in menu area: invalid select" << endl; model->removeSelected(); return; } @@ -80,7 +79,8 @@ void Controller::pressRightArrow() { moveShape(10, 0); } -void Controller::pressGKeyEditMode() { +void Controller::GroupShapes() { + // If only one shape is selected, attempt to ungroup if (model->getSelected().size() == 1) { CompositeShape* c = dynamic_cast(getSelected().at(0)); if (c != NULL) { @@ -105,6 +105,10 @@ void Controller::Redo() { history->Redo(); } +void Controller::setColor(int x) { + model->setColor(x); +} + // ShapesModel void ShapesModel::removeShape(Shape* x) { for (auto i = listShapes.begin(); i != listShapes.end(); i++) { @@ -213,3 +217,22 @@ void ShapesModel::removeSelected() { selected.clear(); } } + +ECGVColor ShapesModel::getColor() { + return color; +} + +void ShapesModel::setColor(int x) { + color = parseColor(x); +} + +void ShapesModel::save() { + if (filename != "") { + ofstream f(filename, std::ios::trunc); + f << getListShapes().size() << endl; + for (auto i : getListShapes()) { + i->writeShape(f); + } + f.close(); + } +} diff --git a/source-files/test-gv.cpp b/source-files/test-gv.cpp index 5fe2018..313da8e 100644 --- a/source-files/test-gv.cpp +++ b/source-files/test-gv.cpp @@ -8,8 +8,6 @@ #include "../header-files/Shape.h" #include "../header-files/Menu.h" #include -#include -#include using namespace std; CompositeShape* parseComposite(int numMembers, ifstream& f, ShapesModel* model) { @@ -40,9 +38,12 @@ int real_main(int argc, char** argv) // Initialize view const int widthWin = 1000, heightWin = 1000; ECGraphicViewImp view(widthWin, heightWin); + + // Get filename from command line args + string filename = (argc == 2) ? argv[1] : ""; // Initialize Model and Controller - ShapesModel* model = new ShapesModel; + ShapesModel* model = new ShapesModel(filename); Controller ctrl(model); // Mouse Functions --> these will be accessed in the menu and in the mouse observers @@ -50,11 +51,10 @@ int real_main(int argc, char** argv) EditModeMouseFunction editMouseFunctionality(view, ctrl); // menu init - Menu* menu = new Menu(editMouseFunctionality, insertMouseFunctionality); - menu->initFont(al_load_ttf_font("IBMPlexSans-Regular.ttf", 18, 0)); - - menu->initDivider(al_load_bitmap("res/divider.jpg")); - menu->initBackground(al_load_bitmap("res/background.jpg")); + Menu menu(editMouseFunctionality, insertMouseFunctionality); + menu.initFont(al_load_ttf_font("IBMPlexSans-Regular.ttf", 18, 0)); + menu.initDivider(al_load_bitmap("res/divider.jpg")); + menu.initBackground(al_load_bitmap("res/background.jpg")); vector buttons; buttons.push_back(al_load_bitmap("res/bt-edit.jpg")); @@ -69,7 +69,7 @@ int real_main(int argc, char** argv) buttons.push_back(al_load_bitmap("res/bt-filled-ellipse.jpg")); buttons.push_back(al_load_bitmap("res/bt-save.jpg")); buttons.push_back(al_load_bitmap("res/bt-help.jpg")); - menu->initButtons(buttons); + menu.initButtons(buttons); vector hoverButtons; hoverButtons.push_back(al_load_bitmap("res/bt-edit-hover.jpg")); @@ -84,7 +84,7 @@ int real_main(int argc, char** argv) hoverButtons.push_back(al_load_bitmap("res/bt-filled-ellipse-hover.jpg")); hoverButtons.push_back(al_load_bitmap("res/bt-save-hover.jpg")); hoverButtons.push_back(al_load_bitmap("res/bt-help-hover.jpg")); - menu->initHoverButtons(hoverButtons); + menu.initHoverButtons(hoverButtons); vector colorButtons; colorButtons.push_back(al_load_bitmap("res/bt-color-black.jpg")); @@ -95,7 +95,7 @@ int real_main(int argc, char** argv) colorButtons.push_back(al_load_bitmap("res/bt-color-yellow.jpg")); colorButtons.push_back(al_load_bitmap("res/bt-color-purple.jpg")); colorButtons.push_back(al_load_bitmap("res/bt-color-cyan.jpg")); - menu->initColorButtons(colorButtons); + menu.initColorButtons(colorButtons); vector hoverColorButtons; hoverColorButtons.push_back(al_load_bitmap("res/bt-color-black-hover.jpg")); @@ -106,7 +106,7 @@ int real_main(int argc, char** argv) hoverColorButtons.push_back(al_load_bitmap("res/bt-color-yellow-hover.jpg")); hoverColorButtons.push_back(al_load_bitmap("res/bt-color-purple-hover.jpg")); hoverColorButtons.push_back(al_load_bitmap("res/bt-color-cyan-hover.jpg")); - menu->initColorHoverButtons(hoverColorButtons); + menu.initColorHoverButtons(hoverColorButtons); // fetches and loads data from file specified via command line if (argc > 1) { @@ -123,7 +123,8 @@ int real_main(int argc, char** argv) } if (x.size() == 2) { model->loadComposite(parseComposite(x.at(1), f, model)); - } else if (x.size() > 2) { + } + else if (x.size() > 2) { model->parseAtomic(x); } } @@ -132,14 +133,16 @@ int real_main(int argc, char** argv) } // Creating observers - ECSpaceObserver* SpaceObserver = new ECSpaceObserver(view, ctrl); - ECDrawObserver* DrawObserver = new ECDrawObserver(view, ctrl); - DrawObserver->attachMenu(menu); // attach menu - ECDObserver* DelObserver = new ECDObserver(view, ctrl); - ECUndoRedoObserver* UndoRedoObserver = new ECUndoRedoObserver(view, ctrl); - ECGObserver* GKeyObserver = new ECGObserver(view, ctrl); - ECFObserver* FKeyObserver = new ECFObserver(view, ctrl); + ECModeObserver* ModeObserver = new ECModeObserver(view, ctrl, menu); + ECDrawObserver* DrawObserver = new ECDrawObserver(view, ctrl, menu); + ECDelObserver* DelObserver = new ECDelObserver(view, ctrl, menu); + ECUndoRedoObserver* UndoRedoObserver = new ECUndoRedoObserver(view, ctrl, menu); + ECGroupObserver* GroupObserver = new ECGroupObserver(view, ctrl, menu); + ECTypeInsertObserver* TypeInsertObserver = new ECTypeInsertObserver(view, ctrl, menu); ECCtrlObserver* CtrlKeyObserver = new ECCtrlObserver(view, ctrl); + ECColorObserver* ColorObserver = new ECColorObserver(view, ctrl, menu); + ECSaveObserver* SaveObserver = new ECSaveObserver(view, ctrl, menu); + ECHelpObserver* HelpObserver = new ECHelpObserver(view, ctrl, menu); ECUpArrowObserver* UpKeyObserver = new ECUpArrowObserver(view, ctrl); ECDownArrowObserver* DownKeyObserver = new ECDownArrowObserver(view, ctrl); ECLeftArrowObserver* LeftKeyObserver = new ECLeftArrowObserver(view, ctrl); @@ -150,15 +153,18 @@ int real_main(int argc, char** argv) ECMouseObserver* InsertModeMouseObserver = new ECMouseObserver(view, ctrl, 1, insertMouseFunctionality); // Attaching observers - view.Attach(SpaceObserver); + view.Attach(ModeObserver); view.Attach(DrawObserver); view.Attach(DelObserver); view.Attach(UndoRedoObserver); - view.Attach(GKeyObserver); - view.Attach(FKeyObserver); + view.Attach(GroupObserver); + view.Attach(TypeInsertObserver); view.Attach(CtrlKeyObserver); view.Attach(EditModeMouseObserver); view.Attach(InsertModeMouseObserver); + view.Attach(ColorObserver); + view.Attach(SaveObserver); + view.Attach(HelpObserver); view.Attach(UpKeyObserver); view.Attach(DownKeyObserver); view.Attach(LeftKeyObserver); @@ -167,33 +173,28 @@ int real_main(int argc, char** argv) // Run application view.Show(); - if (argc == 2) { - ofstream f(argv[1], std::ios::trunc); - f << model->getListShapes().size() << endl; - for (auto i: model->getListShapes()) { - i->writeShape(f); - } - f.close(); - } + // Save before closing + model->save(); // Deallocate pointers - delete SpaceObserver; + delete ModeObserver; delete DrawObserver; delete DelObserver; delete UndoRedoObserver; delete EditModeMouseObserver; - delete GKeyObserver; + delete GroupObserver; + delete TypeInsertObserver; delete CtrlKeyObserver; + delete ColorObserver; + delete SaveObserver; + delete HelpObserver; delete UpKeyObserver; delete DownKeyObserver; delete LeftKeyObserver; delete RightKeyObserver; - delete FKeyObserver; delete InsertModeMouseObserver; delete model; - // destroy allegro components - return 0; } diff --git a/test-files/frog.txt b/test-files/frog.txt index c3345e9..b556dd2 100644 --- a/test-files/frog.txt +++ b/test-files/frog.txt @@ -3,7 +3,6 @@ 0 4 701 541 701 547 1001 547 1001 541 4 1 482 718 246 156 3 1 484 802 10 70 3 -3 134 177 64 62 5 4 11 3 627 782 30 29 2 1 597 764 10 11 2 @@ -60,3 +59,4 @@ 3 628 677 10 24 3 3 653 687 9 24 3 3 678 682 9 25 3 +3 134 177 64 62 5 diff --git a/test-files/test.txt b/test-files/test.txt new file mode 100644 index 0000000..5962bb8 --- /dev/null +++ b/test-files/test.txt @@ -0,0 +1,2 @@ +1 +0 4 179 344 179 592 464 592 464 344 0 diff --git a/test-files/test1.txt b/test-files/test1.txt index 739568d..bf86cb1 100644 --- a/test-files/test1.txt +++ b/test-files/test1.txt @@ -1,34 +1,35 @@ -3 +2 +2 4 361 451 361 449 363 449 363 451 0 +4 2 4 2 4 2 4 3 -2 4 89 215 89 226 160 226 160 215 0 -2 4 89 54 89 226 97 226 97 54 0 -2 4 90 54 90 64 160 64 160 54 0 +2 4 46 352 46 363 117 363 117 352 0 +2 4 46 191 46 363 54 363 54 191 0 +2 4 47 191 47 201 117 201 117 191 0 4 4 -2 4 282 55 282 224 289 224 289 55 0 -2 4 283 129 283 140 362 140 362 129 0 -2 4 285 215 285 224 366 224 366 215 0 -2 4 282 52 282 63 362 63 362 52 0 +2 4 239 192 239 361 246 361 246 192 0 +2 4 240 266 240 277 319 277 319 266 0 +2 4 242 352 242 361 323 361 323 352 0 +2 4 239 189 239 200 319 200 319 189 0 4 5 -2 4 187 52 187 62 255 62 255 52 0 -2 4 247 132 247 224 256 224 256 132 0 -2 4 185 52 185 142 193 142 193 52 0 -2 4 185 132 185 142 256 142 256 132 0 -2 4 189 215 189 224 250 224 250 215 0 +2 4 144 189 144 199 212 199 212 189 0 +2 4 204 269 204 361 213 361 213 269 0 +2 4 142 189 142 279 150 279 150 189 0 +2 4 142 269 142 279 213 279 213 269 0 +2 4 146 352 146 361 207 361 207 352 0 4 14 -2 4 228 408 228 415 298 415 298 408 0 -2 4 68 338 68 345 132 345 132 338 0 -2 4 335 272 335 282 414 282 414 272 0 -2 4 62 273 62 281 136 281 136 273 0 -2 4 336 400 336 413 416 413 416 400 0 -2 4 298 337 298 415 306 415 306 337 0 -2 4 127 273 127 415 137 415 137 273 0 -2 4 225 336 225 343 306 343 306 336 0 -2 4 334 272 334 413 342 413 342 272 0 -2 4 175 272 175 415 185 415 185 272 0 -2 4 225 272 225 281 305 281 305 272 0 -2 4 225 272 225 342 232 342 232 272 0 -2 4 407 273 407 411 416 411 416 273 0 -2 4 66 409 66 416 137 416 137 409 0 -2 4 361 451 361 449 363 449 363 451 0 +2 4 191 519 191 526 261 526 261 519 0 +2 4 31 449 31 456 95 456 95 449 0 +2 4 298 383 298 393 377 393 377 383 0 +2 4 25 384 25 392 99 392 99 384 0 +2 4 299 511 299 524 379 524 379 511 0 +2 4 261 448 261 526 269 526 269 448 0 +2 4 90 384 90 526 100 526 100 384 0 +2 4 188 447 188 454 269 454 269 447 0 +2 4 297 383 297 524 305 524 305 383 0 +2 4 138 383 138 526 148 526 148 383 0 +2 4 188 383 188 392 268 392 268 383 0 +2 4 188 383 188 453 195 453 195 383 0 +2 4 370 384 370 522 379 522 379 384 0 +2 4 29 520 29 527 100 527 100 520 0 diff --git a/test-files/test10.txt b/test-files/test10.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/test-files/test10.txt @@ -0,0 +1 @@ +0