/* * 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 "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_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_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), }; 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(); } MainWindow::~MainWindow() { } void MainWindow::create() { FXMainWindow::create(); INPUT_icon->create(); OUTPUT_icon->create(); AND_icon->create(); NAND_icon->create(); OR_icon->create(); NOR_icon->create(); XOR_icon->create(); XNOR_icon->create(); NOT_icon->create(); canvas_image->create(); show(PLACEMENT_SCREEN); } void MainWindow::create_ui() { contents=new FXHorizontalFrame(this, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y); toolsFrame = new FXVerticalFrame(contents, FRAME_SUNKEN|LAYOUT_FILL_Y|LAYOUT_TOP, 0, 0, 0, 0, 10, 10, 10, 10); 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|FRAME_SUNKEN); scroll_area->setBackColor(canvasFrame->getBackColor()); canvas = new FXCanvas(scroll_area, this, ID_CANVAS, FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FILL_ROW|LAYOUT_FILL_COLUMN); canvas_image = new FXBMPImage(app, NULL, 0, 5000, 5000); new FXLabel(toolsFrame, "Toolbox", NULL, JUSTIFY_CENTER_X|LAYOUT_FILL_X); new FXHorizontalSeparator(toolsFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X); INPUT_icon = new FXGIFIcon(app, INPUT_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); 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); /* tools */ new FXButton(toolsFrame, "", INPUT_icon, this, MainWindow::ID_BUTTON_INPUT, 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, "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); optionsFrame = new FXVerticalFrame(contents, 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)"); } void MainWindow::draw() { FXDCWindow dc_image(canvas_image); dc_image.setFont(getApp()->getNormalFont()); dc_image.setForeground(FXRGB(255, 255, 255)); dc_image.fillRectangle(canvas->getX(), canvas->getY(), canvas->getWidth(), canvas->getHeight()); dc_image.setForeground(FXRGB(0,0,0)); Gate *gate1; /* update every gate */ /* for(auto g1 = gates.begin(); g1 != gates.end(); ++g1) { gate1 = (*g1).get(); gate1->update_state(); } */ /* draw gates */ for(auto g1 = gates.begin(); g1 != gates.end(); ++g1) { gate1 = (*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::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::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; } } /* draw selected gate border box if one is selected */ if (selected_gate != nullptr) { dc_image.drawHashBox(selected_gate->get_x(), selected_gate->get_y(), selected_gate->get_width(), selected_gate->get_height()); } /* draw dragging link */ if (dragging_link && selected_gate) { FXint mousex, mousey; FXuint mbuttons; canvas->getCursorPosition(mousex, mousey, mbuttons); dc_image.drawLine(selected_gate->get_x()+selected_gate->get_width()-5, selected_gate->get_y()+selected_gate->get_height()/2-2, mousex, mousey); } /* draw links */ for(auto g1 = gates.begin(); g1 != gates.end(); ++g1) { /* draw lines from input gate->output gate */ gate1 = (*g1).get(); Gate *in_gate1 = gate1->get_input_gate1(); Gate *in_gate2 = gate1->get_input_gate2(); if (!gate1) continue; if (gate1->get_input_gate1() != nullptr) { if (in_gate1 == selected_input.gate) { 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)); } 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 (gate1->get_input_gate2() != nullptr) { if (in_gate2 == selected_input.gate) { 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 { 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)); } } dc_image.setForeground(FXRGB(0, 0, 0)); } /* update options panel */ if (selected_gate) { input_1_details->setText((selected_gate->get_input_gate1() ? selected_gate->get_input_gate1()->get_output_type_text().c_str() : "(None)")); input_2_details->setText((selected_gate->get_input_gate2() ? selected_gate->get_input_gate2()->get_output_type_text().c_str() : "(None)")); output_details->setText(selected_gate->get_output_state() ? "ON" : "OFF"); } 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); } Gate *MainWindow::find_gate_at(int x, int y) { /* iterate backwards through vector to get box on top */ Gate *returngate = nullptr; Gate *gate = nullptr; int bx, by, bw, bh; for (auto g = gates.rbegin(); g != gates.rend(); ++g) { gate = (*g).get(); bx = gate->get_x(); by = gate->get_y(); bw = gate->get_width(); bh = gate->get_height(); /* check if x,y pos is intersecting with the gate */ if (x >= bx && x <= bx+bw && y >= by && y <= by+bh) { returngate = gate; break; } } return returngate; } Gate *MainWindow::find_gate_by_id(int id) { /* iterate backwards through vector to get box on top */ Gate *gate = nullptr; for (auto g = gates.rbegin(); g != gates.rend(); ++g) { gate = (*g).get(); if (gate->get_id() == id) return gate; } return gate; } void MainWindow::update_gate_state(Gate *gate) { gate->update_state(); /* update all gates that are using this gate as an input */ Gate *gate2; for(auto g = gate->get_output_gates()->begin(); g != gate->get_output_gates()->end(); ++g) { gate2 = find_gate_by_id((*g)); if (gate2) { update_gate_state(gate2); } } } void MainWindow::find_selected_input(int x, int y) { Gate *input_gate = nullptr; if (!selected_gate) { selected_input.gate = nullptr; selected_input.input = -1; return; } int input = -1; if (x >= selected_gate->get_x() && x <= selected_gate->get_x() + 20) { if (y-selected_gate->get_y() <= selected_gate->get_height()/2) { input = 1; } else { input = 2; } switch (input) { case 1: { if (selected_gate->get_input_gate1() != nullptr) { input_gate = selected_gate->get_input_gate1(); } break; } case 2: { if (selected_gate->get_input_gate2() != nullptr) { input_gate = selected_gate->get_input_gate2(); } break; } default: input = -1; break; } if (input_gate != nullptr) { selected_input.gate = input_gate; selected_input.input = input; printf("selected input #%d of gate id %d\n", input, selected_gate->get_id()); } } } 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; selected_input.gate = nullptr; selected_input.input = -1; if (selected_gate_type != Gate::NONE) { /* add new gate */ std::unique_ptr gate(new Gate(selected_gate_type, ev->last_x-70/2, ev->last_y-50/2, 70, 50)); selected_gate = gate.get(); gates.push_back(std::move(gate)); selected_gate_type = Gate::NONE; } else { /* do other things */ /* get gate at cursor */ gate = find_gate_at(ev->last_x, ev->last_y); if (gate) { /* if we found a gate, select it */ selected_gate = gate; if (lshift_down) { dragging_link = true; } update_gate_state(gate); } else { selected_gate = nullptr; selected_input.gate = nullptr; selected_input.input = -1; } if (selected_gate) { /* check if the user clicked on an input and select it */ find_selected_input(ev->last_x, ev->last_y); if (selected_input.gate != nullptr) { /* an input is selected */ } } } 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_gate) { Gate *gate; gate = find_gate_at(ev->last_x, ev->last_y); if (gate == selected_gate) /* gates cannot connect to themselves, probably */ return 1; if (gate) { int input = -1; if (ev->last_y-gate->get_y() <= gate->get_height()/2) input = 1; else input = 2; if (gate->get_gate_type() != Gate::NOT && gate->get_gate_type() && gate->get_gate_type() != Gate::OUTPUT) { printf("connecting gate %d with gate %d at input #%d\n", selected_gate->get_id(), gate->get_id(), input); if (input == 1) { gate->set_input_gate1(selected_gate); } else if (input == 2) { gate->set_input_gate2(selected_gate); } } 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_gate->get_id(), gate->get_id()); gate->set_input_gate1(selected_gate); } } selected_gate->add_output_gate_id(gate->get_id()); update_gate_state(gate); } dragging_link = false; } return 1; } long MainWindow::on_right_mouse_down(FXObject*, FXSelector, void *ptr) { FXEvent *ev = (FXEvent*)ptr; Gate *gate; gate = find_gate_at(ev->last_x, ev->last_y); if (gate) { if (gate->get_gate_type() == Gate::INPUT) { /* toggle state */ gate->set_state(!gate->get_output_state()); } update_gate_state(gate); } 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.gate != nullptr) { switch (selected_input.input) { case 1: selected_gate->get_input_gate1()->remove_output_gate_id(selected_gate->get_id()); selected_gate->set_input_gate1(nullptr); break; case 2: selected_gate->get_input_gate2()->remove_output_gate_id(selected_gate->get_id()); selected_gate->set_input_gate2(nullptr); break; default: break; } update_gate_state(selected_gate); update_gate_state(selected_input.gate); selected_input.gate = nullptr; selected_input.input = -1; draw(); } break; } default: this->onKeyPress(sender, sel, ptr); break; } draw(); return 1; } long MainWindow::on_mouse_move(FXObject *sender, FXSelector sel, void *ptr) { if (lmouse_down && !dragging_link && selected_gate) { FXEvent* event = (FXEvent*)ptr; selected_gate->set_x(event->last_x-selected_gate->get_width()/2); selected_gate->set_y(event->last_y-selected_gate->get_height()/2); } if (lmouse_down) draw(); return 1; } long MainWindow::input_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::INPUT; return 1; } long MainWindow::output_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::OUTPUT; return 1; } long MainWindow::and_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::AND; return 1; } long MainWindow::nand_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::NAND; return 1; } long MainWindow::or_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::OR; return 1; } long MainWindow::xor_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::XOR; return 1; } long MainWindow::nor_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::NOR; return 1; } long MainWindow::xnor_button_press(FXObject *sender, FXSelector sel, void *ptr) { puts("xnor"); selected_gate = nullptr; selected_gate_type = Gate::XNOR; return 1; } long MainWindow::not_button_press(FXObject *sender, FXSelector sel, void *ptr) { selected_gate = nullptr; selected_gate_type = Gate::NOT; return 1; }