/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "MainWindow.h" #include "FXMessageBox.h" #include "FXScrollArea.h" #include "FXScrollBar.h" #include "fxdefs.h" #include #include FXDEFMAP(MainWindow) MainWindow_Map[]= { //________Message_Type____________ID____________Message_Handler_______ FXMAPFUNC(SEL_PAINT, MainWindow::ID_CANVAS, MainWindow::on_paint), FXMAPFUNC(SEL_LEFTBUTTONPRESS, MainWindow::ID_CANVAS, MainWindow::on_left_mouse_down), FXMAPFUNC(SEL_LEFTBUTTONRELEASE, MainWindow::ID_CANVAS, MainWindow::on_left_mouse_up), FXMAPFUNC(SEL_RIGHTBUTTONPRESS, MainWindow::ID_CANVAS, MainWindow::on_right_mouse_down), FXMAPFUNC(SEL_MOTION, MainWindow::ID_CANVAS, MainWindow::on_mouse_move), FXMAPFUNC(SEL_KEYPRESS, 0, MainWindow::on_key_press), FXMAPFUNC(SEL_KEYRELEASE, 0, MainWindow::on_key_release), /* toolbox */ FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_INPUT, MainWindow::input_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_PULSE, MainWindow::pulse_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_OUTPUT, MainWindow::output_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_AND, MainWindow::and_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_NAND, MainWindow::nand_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_3NAND, MainWindow::nand3_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_OR, MainWindow::or_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_NOR, MainWindow::nor_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_XOR, MainWindow::xor_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_XNOR, MainWindow::xnor_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_NOT, MainWindow::not_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_BINARYDISPLAY, MainWindow::binarydisplay_button_press), /* options */ FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_SAVE, MainWindow::save_button_press), FXMAPFUNC(SEL_COMMAND, MainWindow::ID_BUTTON_LOAD, MainWindow::load_button_press), FXMAPFUNC(SEL_IO_READ, MainWindow::ID_UPDATE_OBJECTS, MainWindow::update_objects), }; FXIMPLEMENT(MainWindow, FXMainWindow, MainWindow_Map, ARRAYNUMBER(MainWindow_Map)) MainWindow::MainWindow(FXApp *a) : FXMainWindow(a, "foxlogicgates", nullptr, nullptr, DECOR_ALL, 0, 0, 500, 500) { app = a; create_ui(); sig = new FXGUISignal(app, this, ID_UPDATE_OBJECTS); update_thread = new Thread(this, sig); update_thread->start(); } MainWindow::~MainWindow() { delete update_thread; delete sig; } void MainWindow::create() { FXMainWindow::create(); INPUT_icon->create(); PULSE_icon->create(); OUTPUT_icon->create(); AND_icon->create(); NAND_icon->create(); NAND3_icon->create(); OR_icon->create(); NOR_icon->create(); XOR_icon->create(); XNOR_icon->create(); NOT_icon->create(); BinaryDisplay_icon->create(); canvas_image->create(); show(PLACEMENT_SCREEN); ready_to_draw = true; } void MainWindow::create_ui() { contents = new FXHorizontalFrame(this, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y); /* icons */ INPUT_icon = new FXGIFIcon(app, INPUT_icon_data, IMAGE_KEEP); PULSE_icon = new FXGIFIcon(app, PULSE_icon_data, IMAGE_KEEP); OUTPUT_icon = new FXGIFIcon(app, OUTPUT_icon_data, IMAGE_KEEP); AND_icon = new FXGIFIcon(app, AND_icon_data, IMAGE_KEEP); NAND_icon = new FXGIFIcon(app, NAND_icon_data, IMAGE_KEEP); NAND3_icon = new FXGIFIcon(app, NAND3_icon_data, IMAGE_KEEP); OR_icon = new FXGIFIcon(app, OR_icon_data, IMAGE_KEEP); NOR_icon = new FXGIFIcon(app, NOR_icon_data, IMAGE_KEEP); XOR_icon = new FXGIFIcon(app, XOR_icon_data, IMAGE_KEEP); XNOR_icon = new FXGIFIcon(app, XNOR_icon_data, IMAGE_KEEP); NOT_icon = new FXGIFIcon(app, NOT_icon_data, IMAGE_KEEP); BinaryDisplay_icon = new FXGIFIcon(app, BinaryDisplay_icon_data, IMAGE_KEEP); /* tools */ toolbox_scroll_area = new FXScrollWindow(contents, FX::SCROLLERS_NORMAL|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH, 0, 0, 200); //toolsFrame = new FXVerticalFrame(toolbox_scroll_area, FRAME_SUNKEN|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_FIX_WIDTH, 0, 0, 70); FXPacker *toolsFrame = new FXPacker(toolbox_scroll_area, LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0); new FXLabel(toolsFrame, "Toolbox", NULL, JUSTIFY_CENTER_X|LAYOUT_FILL_X); new FXHorizontalSeparator(toolsFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X); new FXButton(toolsFrame, "", INPUT_icon, this, MainWindow::ID_BUTTON_INPUT, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "", PULSE_icon, this, MainWindow::ID_BUTTON_PULSE, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "", OUTPUT_icon, this, MainWindow::ID_BUTTON_OUTPUT, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "AND", AND_icon, this, MainWindow::ID_BUTTON_AND, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "NAND", NAND_icon, this, MainWindow::ID_BUTTON_NAND, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "3 NAND", NAND3_icon, this, MainWindow::ID_BUTTON_3NAND, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "OR", OR_icon, this, MainWindow::ID_BUTTON_OR, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "NOR", NOR_icon, this, MainWindow::ID_BUTTON_NOR, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "XOR", XOR_icon, this, MainWindow::ID_BUTTON_XOR, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "XNOR", XNOR_icon, this, MainWindow::ID_BUTTON_XNOR, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "NOT", NOT_icon, this, MainWindow::ID_BUTTON_NOT, BUTTON_NORMAL|LAYOUT_FILL_X); new FXButton(toolsFrame, "BinaryDisplay", NULL, this, MainWindow::ID_BUTTON_BINARYDISPLAY, BUTTON_NORMAL|LAYOUT_FILL_X); canvasFrame=new FXVerticalFrame(contents, FRAME_SUNKEN|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 10, 10); new FXLabel(canvasFrame,"foxlogicgates", NULL, JUSTIFY_CENTER_X|LAYOUT_FILL_X); new FXHorizontalSeparator(canvasFrame, SEPARATOR_GROOVE|LAYOUT_FILL_X); scroll_area = new FXScrollWindow(canvasFrame, FX::SCROLLERS_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y); scroll_area->setBackColor(canvasFrame->getBackColor()); FXPacker *canvas_packer = new FXPacker(scroll_area, LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 2048, 2048); canvas = new FXCanvas(canvas_packer, this, ID_CANVAS, LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 2048, 2048); canvas_image = new FXBMPImage(app, NULL, 0, 2048, 2048); /* options */ options_scroll_area = new FXScrollWindow(contents, FX::SCROLLERS_NORMAL|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH, 0, 0, 123); optionsFrame = new FXVerticalFrame(options_scroll_area, FRAME_SUNKEN|LAYOUT_FILL_Y|LAYOUT_TOP, 0, 0, 0, 0, 10, 10, 10, 10); new FXLabel(optionsFrame, "Options", NULL, JUSTIFY_CENTER_X|LAYOUT_FILL_X); new FXHorizontalSeparator(optionsFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X); input1_frame = new FXHorizontalFrame(optionsFrame, LAYOUT_SIDE_TOP); input2_frame = new FXHorizontalFrame(optionsFrame, LAYOUT_SIDE_TOP); output_state_frame = new FXHorizontalFrame(optionsFrame, LAYOUT_SIDE_TOP); new FXLabel(input1_frame, "Input 1: ", NULL, JUSTIFY_CENTER_X); input_1_details = new FXLabel(input1_frame, "", NULL, JUSTIFY_CENTER_X); input_1_details->setText("(None)"); new FXLabel(input2_frame, "Input 2: ", NULL, JUSTIFY_CENTER_X); input_2_details = new FXLabel(input2_frame, "", NULL, JUSTIFY_CENTER_X); input_2_details->setText("(None)"); new FXLabel(output_state_frame, "Output: ", NULL, JUSTIFY_CENTER_X); output_details = new FXLabel(output_state_frame, "", NULL, JUSTIFY_CENTER_X); output_details->setText("(None)"); new FXHorizontalSeparator(optionsFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X); /* save/load */ new FXLabel(optionsFrame, "Save as XML", NULL, JUSTIFY_CENTER_X|LAYOUT_FILL_X); new FXButton(optionsFrame, "Save", nullptr, this, MainWindow::ID_BUTTON_SAVE, BUTTON_NORMAL|LAYOUT_FILL_X); new FXLabel(optionsFrame, "Load from XML", NULL, JUSTIFY_CENTER_X|LAYOUT_FILL_X); new FXButton(optionsFrame, "Load", nullptr, this, MainWindow::ID_BUTTON_LOAD, BUTTON_NORMAL|LAYOUT_FILL_X); } void MainWindow::draw() { lock.lock(); FXDCWindow dc_image(canvas_image); dc_image.setFont(getApp()->getNormalFont()); dc_image.setForeground(FXRGB(255, 255, 255)); dc_image.fillRectangle(canvas->getX()-10, canvas->getY()-10, canvas->getWidth()+10, canvas->getHeight()+10); // -+10 to fix black border dc_image.setForeground(FXRGB(0,0,0)); bool drawn_special_link = false; Gate *gate1; /* draw objects */ for(auto g1 = objects.begin(); g1 != objects.end(); ++g1) { switch ((*g1)->get_object_type()) { case Object::GATE: { gate1 = (Gate*)(*g1).get(); switch(gate1->get_gate_type()) { case Gate::INPUT: { if (gate1->get_output_state() == true) { /* input is switched on, indicate so */ dc_image.setForeground(FXRGB(255, 255, 0)); dc_image.fillRectangle(gate1->get_x(), gate1->get_y(), gate1->get_width(), gate1->get_height()); dc_image.setForeground(FXRGB(0,0,0)); } dc_image.drawIcon(INPUT_icon, gate1->get_x(), gate1->get_y()); break; } case Gate::PULSE: { if (gate1->get_output_state() == true) { /* input is switched on, indicate so */ dc_image.setForeground(FXRGB(255, 255, 0)); dc_image.fillRectangle(gate1->get_x(), gate1->get_y(), gate1->get_width(), gate1->get_height()); dc_image.setForeground(FXRGB(0,0,0)); } dc_image.drawIcon(PULSE_icon, gate1->get_x(), gate1->get_y()); break; } case Gate::OUTPUT: { if (gate1->get_output_state() == true) { /* output is on, indicate so */ dc_image.setForeground(FXRGB(255, 255, 0)); dc_image.fillRectangle(gate1->get_x(), gate1->get_y(), gate1->get_width(), gate1->get_height()); dc_image.setForeground(FXRGB(0,0,0)); } dc_image.drawIcon(OUTPUT_icon, gate1->get_x(), gate1->get_y()); break; } case Gate::AND: { dc_image.drawIcon(AND_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "AND"); break; } case Gate::NAND: { dc_image.drawIcon(NAND_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "NAND"); break; } case Gate::NAND3: { dc_image.drawIcon(NAND3_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "3 Input NAND"); break; } case Gate::OR: { dc_image.drawIcon(OR_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "OR"); break; } case Gate::NOR: { dc_image.drawIcon(NOR_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "NOR"); break; } case Gate::XOR: { dc_image.drawIcon(XOR_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "XOR"); break; } case Gate::XNOR: { dc_image.drawIcon(XNOR_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "XNOR"); break; } case Gate::NOT: { dc_image.drawIcon(NOT_icon, gate1->get_x(), gate1->get_y()); dc_image.drawText(gate1->get_x(), gate1->get_y()+gate1->get_height()+20, "NOT"); break; } case Gate::NONE: default: break; } break; } case Object::BINARYDISPLAY: { class BinaryDisplay *bdsp = (class BinaryDisplay*)(*g1).get(); dc_image.drawIcon(BinaryDisplay_icon, bdsp->get_x(), bdsp->get_y()); dc_image.drawText(bdsp->get_x()+bdsp->get_width()+10, bdsp->get_y()+(bdsp->get_height()/2), FXStringVal(bdsp->get_sum_value())); break; } case Object::NONE: default: printf("implement objects in draw() drawing objects\n"); break; } } /* draw selected gate border box if one is selected */ if (selected_object != nullptr) { dc_image.drawHashBox(selected_object->get_x(), selected_object->get_y(), selected_object->get_width(), selected_object->get_height()); } else if (!selected_objects.empty()) { /* draw border box if multuple gates selected */ Object *selobject; for (auto g = selected_objects.begin(); g != selected_objects.end(); ++g) { selobject = (Object*)(*g); dc_image.drawHashBox(selobject->get_x(), selobject->get_y(), selobject->get_width(), selobject->get_height()); } } /* draw dragging link */ if (dragging_link && selected_object) { FXint mousex, mousey; FXuint mbuttons; canvas->getCursorPosition(mousex, mousey, mbuttons); dc_image.drawLine(selected_object->get_x()+selected_object->get_width()-5, selected_object->get_y()+selected_object->get_height()/2-2, mousex, mousey); } /* draw links */ for(auto g1 = objects.begin(); g1 != objects.end(); ++g1) { /* draw lines from input gate->output gate */ switch ((*g1)->get_object_type()) { case Object::GATE: { gate1 = (Gate*)(*g1).get(); if (!gate1) continue; Object *in_gate1 = gate1->get_input_gate1(); Object *in_gate2 = gate1->get_input_gate2(); Object *in_gate3 = gate1->get_input_gate3(); if (in_gate1 != nullptr) { if (in_gate1 == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } if (gate1->get_gate_type() == Gate::NOT || gate1->get_gate_type() == Gate::OUTPUT) { /* NOT,OUTPUT need a special case */ dc_image.drawLine(in_gate1->get_x()+in_gate1->get_width()-5, in_gate1->get_y()+(in_gate1->get_height()/2), gate1->get_x()+10, gate1->get_y()+(gate1->get_height()/2)); dc_image.setForeground(FXRGB(0, 0, 0)); } /* nand3 gate does not need a special case for the first input */ else { dc_image.drawLine(in_gate1->get_x()+in_gate1->get_width()-5, in_gate1->get_y()+(in_gate1->get_height()/2), gate1->get_x()+10, gate1->get_y()+7); dc_image.setForeground(FXRGB(0, 0, 0)); } } if (in_gate2 != nullptr) { if (in_gate2 == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } if (gate1->get_gate_type() == Gate::NOT || gate1->get_gate_type() == Gate::OUTPUT) { /* NOT,OUTPUT need a special case */ continue; } else if (gate1->get_gate_type() == Gate::NAND3) { /* special case for 3 input gates */ dc_image.drawLine(in_gate2->get_x()+in_gate2->get_width()-5, in_gate2->get_y()+(in_gate2->get_height()/2), gate1->get_x()+10, gate1->get_y()+25); dc_image.setForeground(FXRGB(0, 0, 0)); } else { dc_image.drawLine(in_gate2->get_x()+in_gate2->get_width()-5, in_gate2->get_y()+(in_gate2->get_height()/2), gate1->get_x()+10, gate1->get_y()+43); dc_image.setForeground(FXRGB(0, 0, 0)); } } if (in_gate3 != nullptr) { /* special case for drawing third input gate */ dc_image.drawLine(in_gate3->get_x()+in_gate3->get_width()-5, in_gate3->get_y()+(in_gate3->get_height()/2), gate1->get_x()+10, gate1->get_y()+43); dc_image.setForeground(FXRGB(0, 0, 0)); } dc_image.setForeground(FXRGB(0, 0, 0)); break; } case Object::BINARYDISPLAY: { class BinaryDisplay *bdsp = (class BinaryDisplay*)(*g1).get(); Object *input; if ((input = bdsp->get_input0())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+90); } if ((input = bdsp->get_input1())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+80); } if ((input = bdsp->get_input2())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+66); } if ((input = bdsp->get_input3())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+55); } if ((input = bdsp->get_input4())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+44); } if ((input = bdsp->get_input5())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+33); } if ((input = bdsp->get_input6())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+22); } if ((input = bdsp->get_input7())) { if (input == selected_input.object) { dc_image.setForeground(FXRGB(255, 0, 0)); } dc_image.drawLine(input->get_x()+input->get_width()-5, input->get_y()+(input->get_height()/2), bdsp->get_x()+10, bdsp->get_y()+11); } break; } case Object::NONE: default: printf("draw() implement other objects\n"); break; } dc_image.setForeground(FXRGB(0, 0, 0)); } /*draw rubber band */ if (rubberbanding) { FXint mousex, mousey; FXuint mbuttons; canvas->getCursorPosition(mousex, mousey, mbuttons); dc_image.drawRectangle(rubberband_startx, rubberband_starty, mousex-rubberband_startx, mousey-rubberband_starty); } /* update options panel */ if (selected_object) { switch (selected_object->get_object_type()) { case Object::GATE: { Gate *gate = (Gate*)selected_object; input_1_details->setText((gate->get_input_gate1()) ? gate->get_input_gate1()->get_object_name().c_str() : "(None)"); input_2_details->setText((gate->get_input_gate2()) ? gate->get_input_gate2()->get_object_name().c_str() : "(None)"); output_details->setText(gate->get_output_state() ? "ON" : "OFF"); break; } case Object::BINARYDISPLAY: { ;break; } case Object::NONE: default: printf("otpion panel update object not implemetned\n"); break; } } else { input_1_details->setText("(None)"); input_2_details->setText("(None)"); output_details->setText("(None)"); } FXDCWindow dc_canvas(canvas); dc_canvas.drawImage(canvas_image, 0, 0); lock.unlock(); } Object *MainWindow::find_object_at(int x, int y) { /* iterate backwards through vector to get box on top */ Object *returnobject = nullptr; Object *object = nullptr; int bx, by, bw, bh; for (auto g = objects.rbegin(); g != objects.rend(); ++g) { object = (*g).get(); bx = object->get_x(); by = object->get_y(); bw = object->get_width(); bh = object->get_height(); /* check if x,y pos is intersecting with the object */ if (x >= bx && x <= bx+bw && y >= by && y <= by+bh) { returnobject = object; break; } } return returnobject; } Object *MainWindow::find_object_by_id(int id) { /* iterate backwards through vector to get object on top */ Object *object = nullptr; for (auto g = objects.rbegin(); g != objects.rend(); ++g) { object = (*g).get(); if (object->get_id() == id) return object; } return object; } long MainWindow::update_objects(FXObject*,FXSelector,void* ptr) { lock.lock(); Object *object; for(auto o = objects.begin(); o != objects.end(); ++o) { object = (*o).get(); object->update_state(); } if (ready_to_draw) { lock.unlock(); draw(); lock.lock(); } lock.unlock(); return 1; } void MainWindow::update_object_state(Object *object) { return; object->update_state(); /* update all objects that are using this object as an input */ Object *object2; auto output_objects = object->get_output_objects(); for(auto o = output_objects->begin(); o != output_objects->end(); ++o) { object2 = find_object_by_id((*o)); if (object2) { update_object_state(object2); } } } void MainWindow::find_selected_input(int x, int y) { Object *input_object = nullptr; Object *object = selected_object; if (!selected_object) { selected_input.object = nullptr; selected_input.input = -1; return; } int input = -1; if (x >= selected_object->get_x() && x <= selected_object->get_x() + 20) { switch (selected_object->get_object_type()) { case Object::GATE: { Gate *gate = (Gate*)object; switch (gate->get_gate_type()) { case Gate::NAND3: { puts("nand"); /* 3 input gates */ int relypos = y-gate->get_y(); if (relypos <= 16) { input = 1; input_object = gate->get_input_gate1(); } if (relypos >16 && relypos <= 34) { input = 2; input_object = gate->get_input_gate2(); } if (relypos >34) { input = 3; input_object = gate->get_input_gate3(); } break; } default: { /* 2 or 1 input gates */ if (y-selected_object->get_y() <= selected_object->get_height()/2) { input = 1; } else { input = 2; } switch (input) { case 1: { if (gate->get_input_gate1() != nullptr) { input_object = gate->get_input_gate1(); } break; } case 2: { if (gate->get_input_gate2() != nullptr) { input_object = gate->get_input_gate2(); } else { /* special check for gates with only one input */ if (gate->get_gate_type() == Gate::NOT || gate->get_gate_type() == Gate::OUTPUT) { input_object = gate->get_input_gate1(); input = 1; } } break; } default: input = -1; break; } break; } } break; } case Object::BINARYDISPLAY: { puts("bdsp"); BinaryDisplay *bdsp = (BinaryDisplay*)object; int relypos = y-bdsp->get_y(); if (relypos <= 15) { input = 7; input_object = bdsp->get_input7(); } if (relypos >15 && relypos <= 27) { input = 6; input_object = bdsp->get_input6(); } if (relypos >27 && relypos <= 39) { input = 5; input_object = bdsp->get_input5(); } if (relypos >39 && relypos <= 50) { input = 4; input_object = bdsp->get_input4(); } if (relypos >50 && relypos <= 60) { input = 3; input_object = bdsp->get_input3(); } if (relypos >60 && relypos <= 72) { input = 2; input_object = bdsp->get_input2(); } if (relypos >72 && relypos <= 84) { input = 1; input_object = bdsp->get_input1(); } if (relypos >84 && relypos <= 100) { input = 0; input_object = bdsp->get_input0(); } break; } case Object::NONE: default: printf("find_selected_input() object not implemented\n"); break; } if (input_object != nullptr) { selected_input.object = input_object; selected_input.input = input; printf("selected input #%d of object id %d\n", input, selected_object->get_id()); } } } bool MainWindow::save_file() { FXString filename=FXFileDialog::getSaveFilename(this, "Save", "logicgates.xml", "XML files (*.xml)\nAll Files(*.*)"); if(!filename.empty()) { file_name = filename.text(); printf("saving to %s\n", file_name.c_str()); } else { /* cannot save */ return false; } pugi::xml_document doc; auto declarationNode = doc.append_child(pugi::node_declaration); declarationNode.append_attribute("version") = "1.0"; declarationNode.append_attribute("encoding") = "ISO-8859-1"; declarationNode.append_attribute("standalone") = "yes"; /* write meta data */ auto meta = doc.append_child("Meta"); pugi::xml_node info_xml = meta.append_child("Info"); info_xml.append_attribute("next_id") = Object::get_object_id_counter(); auto root = doc.append_child("Objects"); /* iterate through all objects and add child nodes */ Object *object; for (auto g = objects.begin(); g != objects.end(); ++g) { object = (*g).get(); switch (object->get_object_type()) { case Object::GATE: { pugi::xml_node object_xml = root.append_child("Gate"); Gate *gate; gate = (Gate*)object; object_xml.append_attribute("id") = object->get_id(); object_xml.append_attribute("object_type") = object->get_object_type(); object_xml.append_attribute("x") = object->get_x(); object_xml.append_attribute("y") = object->get_y(); object_xml.append_attribute("w") = object->get_width(); object_xml.append_attribute("h") = object->get_height(); object_xml.append_attribute("gate_type") = gate->get_gate_type(); if (gate->get_input_gate1()) object_xml.append_attribute("input1_id") = gate->get_input_gate1()->get_id(); if (gate->get_input_gate2()) object_xml.append_attribute("input2_id") = gate->get_input_gate2()->get_id(); if (gate->get_input_gate3()) object_xml.append_attribute("input3_id") = gate->get_input_gate3()->get_id(); object_xml.append_attribute("output_state") = gate->get_output_state(); /* iterate through all output gates and write them */ for(auto id = gate->get_output_objects()->begin(); id != gate->get_output_objects()->end(); ++id) { auto outid_node = object_xml.append_child("output_object_id"); outid_node.append_attribute("id") = (*id); } break; } case Object::BINARYDISPLAY: { pugi::xml_node object_xml = root.append_child("BinaryDisplay"); BinaryDisplay *bdsp = (BinaryDisplay*)object; object_xml.append_attribute("id") = object->get_id(); object_xml.append_attribute("object_type") = object->get_object_type(); object_xml.append_attribute("x") = object->get_x(); object_xml.append_attribute("y") = object->get_y(); object_xml.append_attribute("w") = object->get_width(); object_xml.append_attribute("h") = object->get_height(); if (bdsp->get_input0()) object_xml.append_attribute("input0_id") = bdsp->get_input0()->get_id(); if (bdsp->get_input1()) object_xml.append_attribute("input1_id") = bdsp->get_input1()->get_id(); if (bdsp->get_input2()) object_xml.append_attribute("input2_id") = bdsp->get_input2()->get_id(); if (bdsp->get_input3()) object_xml.append_attribute("input3_id") = bdsp->get_input3()->get_id(); if (bdsp->get_input4()) object_xml.append_attribute("input4_id") = bdsp->get_input4()->get_id(); if (bdsp->get_input5()) object_xml.append_attribute("input5_id") = bdsp->get_input5()->get_id(); if (bdsp->get_input6()) object_xml.append_attribute("input6_id") = bdsp->get_input6()->get_id(); if (bdsp->get_input7()) object_xml.append_attribute("input7_id") = bdsp->get_input7()->get_id(); object_xml.append_attribute("output_state") = bdsp->get_output_state(); /* iterate through all output gates and write them */ for(auto id = bdsp->get_output_objects()->begin(); id != bdsp->get_output_objects()->end(); ++id) { auto outid_node = object_xml.append_child("output_object_id"); outid_node.append_attribute("id") = (*id); } break; } case Object::NONE: default: printf("save_file() implement other objects\n"); break; } } bool saved = doc.save_file(file_name.c_str()); if (saved) printf("saved to %s\n", file_name.c_str()); else printf("could not save"); return true; } bool MainWindow::load_file() { FXString filename=FXFileDialog::getOpenFilename(this, "Open", "", "XML files (*.xml)\nAll Files(*.*)"); if(!filename.empty()) { file_name = filename.text(); printf("loading from %s\n", file_name.c_str()); } else { /* cannot load */ return false; } int next_object_id = 0; pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(file_name.c_str(), pugi::parse_default|pugi::parse_declaration); if (!result) { /* failed reading file */ return false; } remove_all_objects(); /* read meta info */ auto meta_objects = doc.child("Meta"); next_object_id = meta_objects.child("Info").attribute("next_id").as_int(); printf("next object id after loading is: %d\n", next_object_id); auto node_objects = doc.child("Objects"); /* read gates */ for (auto node: node_objects.children("Gate")) { int id, x, y, w, h; bool output_state; Gate::GATE_TYPE type; id = node.attribute("id").as_int(); x = node.attribute("x").as_int(); y = node.attribute("y").as_int(); w = node.attribute("w").as_int(); h = node.attribute("h").as_int(); type = (Gate::GATE_TYPE)node.attribute("gate_type").as_int(); output_state = node.attribute("output_state").as_bool(); std::vector output_gate_ids; printf("new gate with id %d\n", id); std::unique_ptr gate(new Gate(type, x, y, w, h, id)); gate->set_state(output_state); /* read output gate ids */ for (auto output_node: node.children("output_object_id")) { int out_id = output_node.attribute("id").as_int(); output_gate_ids.push_back(out_id); } /*set output ids */ for (auto idout = output_gate_ids.begin(); idout != output_gate_ids.end(); ++idout) { gate->add_output_object_id((*idout)); } objects.push_back(std::move(gate)); } /* read binary displays */ for (auto node: node_objects.children("BinaryDisplay")) { int id, x, y, w, h; bool output_state; id = node.attribute("id").as_int(); x = node.attribute("x").as_int(); y = node.attribute("y").as_int(); w = node.attribute("w").as_int(); h = node.attribute("h").as_int(); output_state = node.attribute("output_state").as_bool(); std::vector output_object_ids; printf("new bdsp with id %d\n", id); std::unique_ptr bdsp(new BinaryDisplay(x, y, w, h, id)); bdsp->set_state(output_state); /* read output bdsp ids */ for (auto output_node: node.children("output_object_id")) { int out_id = output_node.attribute("id").as_int(); output_object_ids.push_back(out_id); } /*set output ids */ for (auto idout = output_object_ids.begin(); idout != output_object_ids.end(); ++idout) { bdsp->add_output_object_id((*idout)); } objects.push_back(std::move(bdsp)); } /* iterate again through all gates in the xml file and set input gates if they exist */ for (auto node: node_objects.children("Gate")) { int input1 = -1; int input2 = -1; int input3 = -1; Gate *gate; if (strcmp(node.attribute("input1_id").as_string(), "") != 0) { input1 = node.attribute("input1_id").as_int(); printf("input 1 exists: %d\n", input1); } if (strcmp(node.attribute("input2_id").as_string(), "") != 0) { input2 = node.attribute("input2_id").as_int(); printf("input 2 exists: %d\n", input2); } if (strcmp(node.attribute("input3_id").as_string(), "") != 0) { input3 = node.attribute("input3_id").as_int(); printf("input 3 exists: %d\n", input2); } gate = (Gate*)find_object_by_id(node.attribute("id").as_int()); /* set inputs */ if (input1 != -1) { gate->set_input_gate1(find_object_by_id(input1)); } if (input2 != -1) { gate->set_input_gate2(find_object_by_id(input2)); } if (input3 != -1) { gate->set_input_gate3(find_object_by_id(input3)); } } /* iterate again through all bdsp's in the xml file and set output objects if they exist */ for (auto node: node_objects.children("BinaryDisplay")) { int input0 = -1; int input1 = -1; int input2 = -1; int input3 = -1; int input4 = -1; int input5 = -1; int input6 = -1; int input7 = -1; BinaryDisplay *bdsp; if (strcmp(node.attribute("input0_id").as_string(), "") != 0) { input0 = node.attribute("input0_id").as_int(); printf("input 0 exists: %d\n", input0); } if (strcmp(node.attribute("input1_id").as_string(), "") != 0) { input1 = node.attribute("input1_id").as_int(); printf("input 1 exists: %d\n", input1); } if (strcmp(node.attribute("input2_id").as_string(), "") != 0) { input2 = node.attribute("input2_id").as_int(); printf("input 2 exists: %d\n", input2); } if (strcmp(node.attribute("input3_id").as_string(), "") != 0) { input3 = node.attribute("input3_id").as_int(); printf("input 3 exists: %d\n", input3); } if (strcmp(node.attribute("input4_id").as_string(), "") != 0) { input4 = node.attribute("input4_id").as_int(); printf("input 4 exists: %d\n", input4); } if (strcmp(node.attribute("input5_id").as_string(), "") != 0) { input5 = node.attribute("input5_id").as_int(); printf("input 5 exists: %d\n", input5); } if (strcmp(node.attribute("input6_id").as_string(), "") != 0) { input6 = node.attribute("input6_id").as_int(); printf("input 6 exists: %d\n", input6); } if (strcmp(node.attribute("input7_id").as_string(), "") != 0) { input7 = node.attribute("input7_id").as_int(); printf("input 7 exists: %d\n", input7); } bdsp = (BinaryDisplay*)find_object_by_id(node.attribute("id").as_int()); /* set inputs */ if (input0 != -1) { bdsp->set_input0(find_object_by_id(input0)); } if (input1 != -1) { bdsp->set_input1(find_object_by_id(input1)); } if (input2 != -1) { bdsp->set_input2(find_object_by_id(input2)); } if (input3 != -1) { bdsp->set_input3(find_object_by_id(input3)); } if (input4 != -1) { bdsp->set_input4(find_object_by_id(input4)); } if (input5 != -1) { bdsp->set_input5(find_object_by_id(input5)); } if (input6 != -1) { bdsp->set_input6(find_object_by_id(input6)); } if (input7 != -1) { bdsp->set_input7(find_object_by_id(input7)); } bdsp->update_state(); } /* set object id counter */ Object::set_object_id_counter(next_object_id); draw(); return true; } void MainWindow::remove_all_objects() { objects.clear(); selected_object = nullptr; selected_input.object = nullptr; selected_input.input = -1; Object::set_object_id_counter(0); draw(); } void MainWindow::find_objects_in_area(int x, int y, int width, int height) { /* * find all gates in a given rectangle */ Object *object; int gx, gy, gw, gh; for (auto g = objects.begin(); g != objects.end(); ++g) { object = (*g).get(); gx = object->get_x(); gy = object->get_y(); gw = object->get_width(); gh = object->get_height(); /* check if rectangles intersect */ if(gx < x+width && gx+gw > x && gy < y+height && gy+gh > y) { printf("adding object %d to selected objects list\n", object->get_id()); selected_objects.push_back(object); } if (!selected_objects.empty()) { selected_object = nullptr; selected_input.object = nullptr; selected_input.input = -1; } } } void MainWindow::remove_object(Object &object) { Object *out_object; switch (object.get_object_type()) { case Object::GATE: { Gate &gate = (Gate&)object; /* delete inputs */ if (gate.get_input_gate1()) { gate.get_input_gate1()->remove_output_object_id(gate.get_id()); update_object_state(gate.get_input_gate1()); } if (gate.get_input_gate2()) { gate.get_input_gate2()->remove_output_object_id(gate.get_id()); update_object_state(gate.get_input_gate2()); } if (gate.get_input_gate3()) { gate.get_input_gate3()->remove_output_object_id(gate.get_id()); update_object_state(gate.get_input_gate3()); } break; } case Object::BINARYDISPLAY: { BinaryDisplay &bdsp = (BinaryDisplay&)object; if (bdsp.get_input0()) { bdsp.get_input0()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input0()); } if (bdsp.get_input1()) { bdsp.get_input1()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input1()); } if (bdsp.get_input2()) { bdsp.get_input2()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input2()); } if (bdsp.get_input3()) { bdsp.get_input3()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input3()); } if (bdsp.get_input4()) { bdsp.get_input4()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input4()); } if (bdsp.get_input5()) { bdsp.get_input5()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input5()); } if (bdsp.get_input6()) { bdsp.get_input6()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input6()); } if (bdsp.get_input7()) { bdsp.get_input7()->remove_output_object_id(bdsp.get_id()); update_object_state(bdsp.get_input7()); } break; } case Object::NONE: default: printf("remove_object implement other objects\n"); break; } /* delete outputs */ for(auto g = object.get_output_objects()->begin(); g != object.get_output_objects()->end(); ++g) { out_object = find_object_by_id((*g)); if (!out_object) continue; out_object->remove_input_object(object.get_id()); update_object_state(out_object); } int pos = 0; for (auto g = objects.begin(); g != objects.end(); ++g) { out_object = (*g).get(); if (out_object->get_id() == object.get_id()) { objects.erase(objects.begin() + pos); break; } pos++; } } long MainWindow::on_paint(FXObject*, FXSelector, void *ptr) { draw(); return 1; } long MainWindow::on_left_mouse_down(FXObject*, FXSelector, void *ptr) { FXEvent *ev = (FXEvent*)ptr; lmouse_down = true; Gate *gate = nullptr; Object *object = nullptr; selected_input.object = nullptr; selected_input.input = -1; if (selected_object_type != Object::NONE) { /* add new object */ switch (selected_object_type) { case Object::GATE: { std::unique_ptr gate(new Gate(selected_gate_type, ev->last_x-70/2, ev->last_y-50/2, 70, 50)); selected_object = gate.get(); objects.push_back(std::move(gate)); selected_object_type = Object::NONE; break; } case Object::BINARYDISPLAY: { std::unique_ptr binarydisplay(new class BinaryDisplay(ev->last_x-70/2, ev->last_y-50/2, 50, 100)); selected_object = binarydisplay.get(); objects.push_back(std::move(binarydisplay)); selected_object_type = Object::NONE; break; } case Object::NONE: default: printf("Object not implemented. lmouse down\n"); } } else { /* do other things */ /* get object at cursor */ object = find_object_at(ev->last_x, ev->last_y); if (object) { if (object && selected_objects.empty()) { /* if we found an object, select it */ selected_object = object; if (lshift_down) { dragging_link = true; } update_object_state(object); } } else { selected_object = nullptr; selected_input.object = nullptr; selected_input.input = -1; } if (selected_object) { /* check if the user clicked on an input and select it */ find_selected_input(ev->last_x, ev->last_y); if (selected_input.object != nullptr) { /* an input is selected */ } } else if (selected_objects.empty()) // TODO: maybe we want to allow rubberbanding when gates are already selected? { rubberbanding = true; rubberband_startx = ev->last_x; rubberband_starty = ev->last_y; } if (!selected_objects.empty()) { if (!object) { selected_objects.clear(); } else { Gate *selgate; bool found_gate = false; /* clear selection if we're not clicking on a selected gate */ for (auto g = selected_objects.begin(); g != selected_objects.end(); ++g) { selgate = (Gate*)(*g); if (object->get_id() == selgate->get_id()) { found_gate = true; } } if (!found_gate) { selected_objects.clear(); } } } } draw(); return 1; } long MainWindow::on_left_mouse_up(FXObject*, FXSelector, void *ptr) { FXEvent *ev = (FXEvent*)ptr; lmouse_down = false; if (lshift_down && dragging_link && selected_object) { Object *object; object = find_object_at(ev->last_x, ev->last_y); if (object) { if (object == selected_object) /* objects cannot connect to themselves, probably */ return 1; switch (object->get_object_type()) { case Object::GATE: { Gate *gate = (Gate*)object; if (gate && gate->get_gate_type() != Gate::INPUT) { int input = -1; switch (gate->get_gate_type()) { case Gate::NAND3: { /* case for gates with 3 inputs */ int relypos = ev->last_y-gate->get_y(); if (relypos <= 16) { input = 1; } if (relypos >16 && relypos <= 34) { input = 2; } if (relypos >34) { input = 3; } break; } default: { if (ev->last_y-gate->get_y() <= gate->get_height()/2) input = 1; else input = 2; break; } } if (gate->get_gate_type() != Gate::NOT && gate->get_gate_type() != Gate::OUTPUT) { // FIXME: these should be objects, cannot explicitly cast to gates printf("connecting gate %d with gate %d at input #%d\n", selected_object->get_id(), gate->get_id(), input); if (input == 1) { gate->set_input_gate1((Gate*)selected_object); } else if (input == 2) { gate->set_input_gate2((Gate*)selected_object); } else if (input == 3) { gate->set_input_gate3((Gate*)selected_object); } } else { /* NOT,NOR,OUTPUT gates needs a special case */ if (input == 1 || input == 2) { printf("connecting gate %d with gate %d at input #1\n", selected_object->get_id(), gate->get_id()); gate->set_input_gate1((Gate*)selected_object); } } selected_object->add_output_object_id(gate->get_id()); update_object_state(gate); } break; } case Object::BINARYDISPLAY: { /* connect object to bdsp input */ class BinaryDisplay *bdsp = (class BinaryDisplay*)object; /* figure out which input we're connecting to */ int input = -1; int gap = 13; if (ev->last_y-bdsp->get_y() <= gap) { input = 7; puts("input 7"); bdsp->set_input7(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } else if (ev->last_y-(bdsp->get_y()+(gap * 1)) <= gap) { input = 6; puts("input 6"); bdsp->set_input6(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } else if (ev->last_y-(bdsp->get_y()+(gap * 2)) <= gap) { input = 5; puts("input 5"); bdsp->set_input5(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } else if (ev->last_y-(bdsp->get_y()+(gap * 3)) <= gap) { input = 4; puts("input 4"); bdsp->set_input4(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } else if (ev->last_y-(bdsp->get_y()+(gap * 4)) <= gap) { input = 3; puts("input 3"); bdsp->set_input3(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } else if (ev->last_y-(bdsp->get_y()+(gap * 5)) <= gap) { input = 2; puts("input 2"); bdsp->set_input2(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } else if (ev->last_y-(bdsp->get_y()+(gap * 6)) <= gap) { input = 1; puts("input 1"); bdsp->set_input1(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } else if (ev->last_y-(bdsp->get_y()+(gap * 7)) <= gap) { input = 0; puts("input 0"); bdsp->set_input0(selected_object); selected_object->add_output_object_id(bdsp->get_id()); update_object_state(bdsp); } break; } case Object::NONE: default: printf("not implemented object left down link\n"); break; } } dragging_link = false; } if (rubberbanding) { rubberbanding = false; multiple_move_startx = ev->last_x; multiple_move_starty = ev->last_y; find_objects_in_area(rubberband_startx, rubberband_starty, ev->last_x-rubberband_startx, ev->last_y-rubberband_starty); draw(); } return 1; } long MainWindow::on_right_mouse_down(FXObject*, FXSelector, void *ptr) { FXEvent *ev = (FXEvent*)ptr; Object *object; object = find_object_at(ev->last_x, ev->last_y); if (object) { switch (object->get_object_type()) { case Object::GATE: { Gate *gate = (Gate*)object; if (gate->get_gate_type() == Gate::INPUT || gate->get_gate_type() == Gate::PULSE) { /* toggle state */ gate->set_state(!gate->get_output_state()); } break; } case Object::NONE: default: printf("rmouse down objects not implemented\n"); break; } update_object_state(object); } draw(); return 1; } long MainWindow::on_key_press(FXObject *sender, FXSelector sel, void *ptr) { FXEvent* event=(FXEvent*)ptr; switch(event->code) { case KEY_Shift_L: lshift_down = true; break; default: this->onKeyPress(sender, sel, ptr); break; } draw(); return 1; } long MainWindow::on_key_release(FXObject *sender, FXSelector sel, void *ptr) { FXEvent* event=(FXEvent*)ptr; switch(event->code) { case KEY_Shift_L: lshift_down = false; dragging_link = false; break; case KEY_Delete: { if (selected_input.object != nullptr) { /* delete link */ switch (selected_object->get_object_type()) { case Object::GATE: { Gate *gate = (Gate*)selected_object; switch (selected_input.input) { case 1: gate->get_input_gate1()->remove_output_object_id(selected_object->get_id()); gate->set_input_gate1(nullptr); break; case 2: gate->get_input_gate2()->remove_output_object_id(selected_object->get_id()); gate->set_input_gate2(nullptr); break; case 3: gate->get_input_gate3()->remove_output_object_id(selected_object->get_id()); gate->set_input_gate3(nullptr); break; default: break; } break; } case Object::BINARYDISPLAY: { BinaryDisplay &bdsp = (BinaryDisplay&)*selected_object; switch (selected_input.input) { case 0: bdsp.get_input0()->remove_output_object_id(bdsp.get_id()); bdsp.set_input0(nullptr); break; case 1: bdsp.get_input1()->remove_output_object_id(bdsp.get_id()); bdsp.set_input1(nullptr); break; case 2: bdsp.get_input2()->remove_output_object_id(bdsp.get_id()); bdsp.set_input2(nullptr); break; case 3: bdsp.get_input3()->remove_output_object_id(bdsp.get_id()); bdsp.set_input3(nullptr); break; case 4: bdsp.get_input4()->remove_output_object_id(bdsp.get_id()); bdsp.set_input4(nullptr); break; case 5: bdsp.get_input5()->remove_output_object_id(bdsp.get_id()); bdsp.set_input5(nullptr); break; case 6: bdsp.get_input6()->remove_output_object_id(bdsp.get_id()); bdsp.set_input6(nullptr); break; case 7: bdsp.get_input7()->remove_output_object_id(bdsp.get_id()); bdsp.set_input7(nullptr); break; default: puts("input not handled in bdsp"); break; } break; } case Object::NONE: default: printf("remove selected input not implemented for object\n"); break; } update_object_state(selected_object); update_object_state(selected_input.object); selected_input.object = nullptr; selected_input.input = -1; draw(); } else if (selected_object) { remove_object(*selected_object); selected_object = nullptr; } else if (!selected_objects.empty()) { /* deleted multiple gates */ for (auto g = selected_objects.begin(); g != selected_objects.end(); ++g) { remove_object(*(*g)); } } break; } default: this->onKeyPress(sender, sel, ptr); break; } draw(); return 1; } long MainWindow::on_mouse_move(FXObject *sender, FXSelector sel, void *ptr) { FXEvent* event = (FXEvent*)ptr; if (lmouse_down && !dragging_link && selected_object) { Coord currentPos { event->last_x, event->last_y }; auto diff = currentPos - lastPos; selected_object->set_x(selected_object->get_x() + diff.X); selected_object->set_y(selected_object->get_y() + diff.Y); } else if (lmouse_down && !dragging_link && !selected_objects.empty()) { Coord currentPos { event->last_x, event->last_y }; auto diff = currentPos - lastPos; /* moving multiple gates */ for (auto* gate : selected_objects) { int gx = gate->get_x(); int gy = gate->get_y(); gate->set_x(diff.X + gx); gate->set_y(diff.Y + gy); } } if (lmouse_down) draw(); lastPos = { event->last_x, event->last_y }; return 1; } long MainWindow::input_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::INPUT; return 1; } long MainWindow::pulse_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::PULSE; return 1; } long MainWindow::output_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::OUTPUT; return 1; } long MainWindow::and_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::AND; return 1; } long MainWindow::nand_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::NAND; return 1; } long MainWindow::nand3_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::NAND3; return 1; } long MainWindow::or_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::OR; return 1; } long MainWindow::xor_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::XOR; return 1; } long MainWindow::nor_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::NOR; return 1; } long MainWindow::xnor_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::XNOR; return 1; } long MainWindow::not_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::GATE; selected_gate_type = Gate::NOT; return 1; } long MainWindow::binarydisplay_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_object = nullptr; selected_object_type = Object::BINARYDISPLAY; return 1; } long MainWindow::save_button_press(FXObject *sender, FXSelector sel, void *ptr) { save_file(); return 1; } long MainWindow::load_button_press(FXObject *sender, FXSelector sel, void *ptr) { load_file(); return 1; }