/home/enzo/treballs/fib/pfc/nanocomp/src/layoutCanvas.cpp

Go to the documentation of this file.
00001 /*
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   This program is distributed in the hope that it will be useful,       *
00009  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00010  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00011  *   GNU General Public License for more details.                          *
00012  *                                                                         *
00013  *   You should have received a copy of the GNU General Public License     *
00014  *   along with this program; if not, write to the                         *
00015  *   Free Software Foundation, Inc.,                                       *
00016  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00017                                                                           */
00018 
00019 // $Revision: 1.25 $
00020 
00021 #include "layoutCanvas.hpp"
00022 #include <wx/dcbuffer.h>
00023 
00024 #define NUMTRANSITIONS 25
00025 #define TIMERINTERVAL 15
00026 #define CELL_SIZE 18
00027 
00028 enum
00029 {
00030     TIMER_ID
00031 };
00032 
00033 //Custom event
00034 DEFINE_EVENT_TYPE( LAYOUT_CANVAS_ACTION )
00035 
00036 
00037 
00038 
00042 LayoutCanvasEvent::LayoutCanvasEvent(wxEventType commandType, int id)
00043     : wxNotifyEvent( commandType, id )
00044 {
00045     x = 0;
00046     y = 0;
00047 }
00048 
00049 
00051 
00054 int LayoutCanvasEvent::getX()
00055 {
00056     return x;
00057 }
00058 
00059 
00061 
00064 int LayoutCanvasEvent::getY()
00065 {
00066     return y;
00067 }
00068 
00069 
00071 
00074 void LayoutCanvasEvent::setX(int x)
00075 {
00076     this->x = x;
00077 }
00078 
00079 
00081 
00084 void LayoutCanvasEvent::setY(int y)
00085 {
00086     this->y = y;
00087 }
00088 
00089 
00090 BEGIN_EVENT_TABLE(LayoutCanvas, wxWindow)
00091     EVT_PAINT(LayoutCanvas::OnPaint)
00092     EVT_LEFT_DOWN(LayoutCanvas::OnLeftDown)
00093     EVT_SCROLLWIN(LayoutCanvas::OnScroll)
00094     EVT_SIZE(LayoutCanvas::OnResize)
00095     EVT_TIMER(TIMER_ID, LayoutCanvas::OnTimer)
00096 END_EVENT_TABLE()
00097 
00098 
00100 
00105 LayoutCanvas::LayoutCanvas(wxWindow *parent, wxWindowID id, Grid initialLayout)
00106     : wxWindow( parent, id, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE | wxSUNKEN_BORDER), layout(initialLayout), previous(initialLayout), chrono(this, TIMER_ID)
00107 {
00108     width = initialLayout.getWidth();
00109     height = initialLayout.getHeight();
00110     cellSize = CELL_SIZE;
00111     scrollX = 0;
00112     scrollY = 0;
00113     centerX  = 0;
00114     centerY = 0;
00115     adjustScrollbars();
00116     adjustCenter();
00117     SetMinSize(wxSize(100, 100));
00118     enableds = true;
00119     disableds = true;
00120     inputs = true;
00121     outputs = true;
00122     spaces = true;
00123     initTransitions();
00124     resetTransitions(NUMTRANSITIONS -1);
00125     drawScene();
00126     transition = false;
00127     chrono.Start(TIMERINTERVAL, false);
00128 }
00129 
00130 
00132 LayoutCanvas::~LayoutCanvas()
00133 {  
00134 }
00135 
00136 
00138 
00142 void LayoutCanvas::OnPaint(wxPaintEvent& WXUNUSED (event))
00143 {
00144         wxBufferedPaintDC dc(this);
00145         clear(dc);
00146         drawGrid(dc);
00147         drawCells(dc);
00148         drawIO(dc);
00149         drawMargins(dc);
00150 }
00151 
00152 
00154 
00159 void LayoutCanvas::OnLeftDown(wxMouseEvent& event)
00160 {
00161     if (!transition) //We do not consider event if we are in a painting transition
00162     {
00163         //Get the logic coordinate of the click
00164         int widgetWidth;
00165         int widgetHeight;
00166         GetClientSize(&widgetWidth, &widgetHeight);
00167         coordinate view;
00168         view.x = event.GetX();
00169         view.y = event.GetY();
00170         coordinate real = viewToReal(view);
00171      
00172         //Send the event if the click was on a cell, nothing if the click was outbounds
00173         if ((real.x >= 0) && (real.x < width) && (real.y >= 0) && (real.y < height))
00174         {
00175             LayoutCanvasEvent event( LAYOUT_CANVAS_ACTION, GetId() );
00176             event.SetEventObject( this );
00177             event.setX(real.x);
00178             event.setY(real.y);
00179             GetEventHandler()->ProcessEvent( event );
00180         }
00181     }
00182 }
00183 
00184 
00186 
00191 void LayoutCanvas::adjustScrollbars()
00192 {
00193     int widgetWidth;
00194     int widgetHeight;
00195     GetClientSize(&widgetWidth, &widgetHeight);
00196 
00197     //See wxWindows documentation for details
00198     //the last parameter of the call is the total width/height of the window
00199     //the width last sum is because we paint the cells in an isometric view,
00200     //so as the grid grows in height, it also grows in width because the new
00201     //lines are painted shifted to the right
00202     SetScrollbar(wxHORIZONTAL, 0, widgetWidth, width*cellSize + (cellSize/2) * height);
00203     SetScrollbar(wxVERTICAL, 0, widgetHeight, height*cellSize);
00204     adjustCenter();
00205     drawScene();  
00206 }
00207 
00208 
00210 
00216 void LayoutCanvas::OnScroll(wxScrollWinEvent& event)
00217 {
00218     WXTYPE type = (WXTYPE)event.GetEventType();
00219     int pos     = event.GetPosition();
00220     int orient  = event.GetOrientation();
00221 
00222     if (type == wxEVT_SCROLLWIN_THUMBTRACK)
00223     {
00224         if (orient == wxHORIZONTAL)
00225         {
00226             //Set the horizontal shift
00227             scrollX = -pos;
00228         }
00229         else
00230         {
00231             //Set the vertical shift
00232             scrollY = -pos;
00233         }
00234     }
00235     drawScene();
00236 }
00237 
00238 
00240 
00246 void LayoutCanvas::drawScene()
00247 {
00248         wxClientDC dc(this);
00249         wxBufferedDC bdc(&dc);
00250         clear(bdc);
00251         drawGrid(bdc);
00252         drawMargins(bdc);
00253         drawCells(bdc);
00254         drawIO(bdc);
00255 }
00256 
00257 
00259 
00264 void LayoutCanvas::OnResize(wxSizeEvent& event)
00265 {
00266     adjustCenter();
00267     adjustScrollbars();
00268     drawScene();
00269 }
00270 
00271 
00273 
00278 void LayoutCanvas::adjustCenter()
00279 {
00280     int widgetWidth;
00281     int widgetHeight;
00282     GetClientSize(&widgetWidth, &widgetHeight);
00283 
00284     if (widgetWidth > (width * cellSize + (cellSize/2) * height))
00285     {
00286         centerX = (widgetWidth / 2) - ((width * cellSize + (cellSize / 2) * height)) / 2;
00287     }
00288     else
00289     {
00290         centerX = 0;
00291     }
00292     if (widgetHeight > (height * cellSize))
00293     {
00294         centerY = (widgetHeight / 2) - ((height * cellSize)) / 2;
00295     }
00296     else
00297     {
00298         centerY = 0;
00299     }
00300 }
00301 
00302 
00304 
00310 coordinate LayoutCanvas::viewToReal(coordinate view)
00311 {
00312         int row = (view.y - centerY - scrollY) / cellSize;
00313     coordinate result;
00314     if ((view.x < centerX + scrollX + row * cellSize/2) || (view.y < centerY + scrollY) || (view.x > width * cellSize + centerX + scrollX + row * cellSize/2) || (view.y > height * cellSize + centerY + scrollY))
00315     {
00316         result.x = -1;
00317         result.y = -1;
00318     }
00319     else
00320     {
00321         result.y = (view.y - centerY - scrollY) / cellSize;
00322         result.x = (view.x - centerX - scrollX - result.y * cellSize / 2) / cellSize;
00323     }
00324     
00325     return result;
00326 }
00327 
00328 
00330 
00336 coordinate LayoutCanvas::realToView(coordinate real)
00337 {
00338     coordinate result;
00339     result.x = (real.x * cellSize) + centerX + scrollX + cellSize / 2 + real.y * cellSize / 2;
00340     result.y = (real.y * cellSize) + centerY + scrollY + cellSize / 2;
00341 
00342     return result;
00343 }
00344 
00345 
00347 
00353 void LayoutCanvas::drawCell(int i, int j, wxColour color, wxDC &dc)
00354 {  
00355     //Calculate the window coordinates
00356     coordinate real;
00357     real.x = i;
00358     real.y = j;
00359     coordinate view;
00360     view = realToView(real);
00361     //Paint
00362     dc.SetPen(wxPen(color));
00363     dc.SetBrush(wxBrush(color));
00364     dc.DrawCircle(view.x, view.y, cellSize / 2 - 1);
00365 }
00366 
00367 
00369 
00373 void LayoutCanvas::setCellSize(int newCellSize)
00374 {
00375     if (newCellSize >= 4)
00376     {
00377         cellSize = newCellSize;
00378         adjustScrollbars();
00379         adjustCenter();
00380     }
00381 }
00382 
00383 
00385 
00390 void LayoutCanvas::drawGrid(wxDC &dc)
00391 {
00392     dc.SetBackground(*wxWHITE_BRUSH);
00393     dc.SetPen(*wxWHITE_PEN);
00394     dc.SetBrush(*wxBLACK_BRUSH);
00395 
00396     for (int i = 0; i < width; i++)
00397     {
00398         for (int j = 0; j < height; j ++)
00399         {
00400             dc.DrawCircle(scrollX + centerX + i * cellSize + cellSize / 2 + j * cellSize / 2, scrollY + centerY + j * cellSize + cellSize / 2, 3);
00401         }
00402     }
00403 }
00404 
00405 
00407 
00410 void LayoutCanvas::drawCells(wxDC &dc)
00411 {
00412     //Draw Cells
00413     //We use a transition system. When a cell has it's status
00414     //changed it doesn't get repainted in the new colour
00415     //immediately, it gets a transition between the previous
00416     //colour and the new one. This is achieved by mantaining
00417     //two grids: the previous and the current, and a third grid
00418     //which saves the transition percent reached in this gradual
00419     //colour change. So, when a cell is painted, the initial and final
00420     //colours are accessed, and then the resulting colour is
00421     //calculated based on the percent. The percent grid is
00422     //refreshed by a timer, controlling the transition duration.
00423     wxColour initial;
00424     wxColour final;
00425     for (int i = 0; i < layout.getWidth(); i++)
00426     {
00427         for (int j = 0; j < layout.getHeight(); j++)
00428         {
00429             //Set initial colour
00430             switch (previous(i, j))
00431             {
00432                 case nENABLED:
00433                 {
00434                     initial = wxColour(*wxRED);
00435                     break;
00436                 }
00437                 case nDISABLED:
00438                 {
00439                     initial = wxColour(*wxBLACK);
00440                     break;
00441                 }
00442                 case nINPUT:
00443                 {
00444                     initial = wxColour(*wxGREEN);
00445                     break;
00446                 }
00447                 case nOUTPUT:
00448                 {
00449                     initial = wxColour(*wxCYAN);
00450                     break;
00451                 }
00452                 case nNOSPACE:
00453                 {
00454                     initial = wxColour(*wxLIGHT_GREY);
00455                     break;
00456                 }
00457                 case nDONTCARE:
00458                 {
00459                     initial = wxColour(*wxWHITE);
00460                     break;
00461                 }
00462             }
00463             //Set final colour and paint if necessary
00464             switch (layout(i, j))
00465             {
00466                 case nENABLED:
00467                 {
00468                     final = wxColour(*wxRED);
00469                     if (enableds)
00470                     {
00471                         drawCell(i, j, calculateColour(initial, final, transitions[i][j]), dc);
00472                     }
00473                     break;
00474                 }
00475                 case nDISABLED:
00476                 {
00477                     final = wxColour(*wxBLACK);
00478                     if (disableds)
00479                     {
00480                         drawCell(i, j, calculateColour(initial, final, transitions[i][j]), dc);
00481                     }
00482                     break;
00483                 }
00484                 case nINPUT:
00485                 {
00486                     final = wxColour(*wxGREEN);
00487                     if (inputs)
00488                     {
00489                         drawCell(i, j, calculateColour(initial, final, transitions[i][j]), dc);
00490                     }
00491                     break;
00492                 }
00493                 case nOUTPUT:
00494                 {
00495                     final = wxColour(*wxCYAN);
00496                     if (outputs)
00497                     {
00498                         drawCell(i, j, calculateColour(initial, final, transitions[i][j]), dc);
00499                     }
00500                     break;
00501                 }
00502                 case nNOSPACE:
00503                 {
00504                     final = wxColour(*wxLIGHT_GREY);
00505                     if (spaces)
00506                     {
00507                         drawCell(i, j, calculateColour(initial, final, transitions[i][j]), dc);
00508                     }
00509                     break;
00510                 }
00511                 case nDONTCARE:
00512                 {
00513                     final = wxColour(*wxWHITE);
00514                     break;
00515                 }
00516             }
00517         }
00518     }
00519 }
00520 
00521 
00523 
00528 void LayoutCanvas::setFittingCellSize()
00529 {
00530     int widgetWidth;
00531     int widgetHeight;
00532     GetClientSize(&widgetWidth, &widgetHeight);
00533     
00534     if (widgetWidth > widgetHeight)
00535     {
00536         setCellSize(widgetHeight / height);
00537     }
00538     else
00539     {
00540         setCellSize(widgetWidth / width + 1);
00541     }
00542 }
00543 
00544 
00546 
00551 void LayoutCanvas::setGrid(Grid newGrid, bool changed)
00552 {
00553     //Previous grid = actual grid
00554     previous.init(layout);
00555     //Actual grid = new grid
00556     layout.init(newGrid);
00557     //Reset the transitions grid
00558     initTransitions();
00559     resetTransitions(0);
00560     if (changed || (previous.getHeight() != newGrid.getHeight()) || (previous.getWidth() != newGrid.getWidth()))
00561     {
00562         //We must reset both layouts because they have different width and heights
00563         previous.init(newGrid);
00564         width = newGrid.getWidth();
00565         height = newGrid.getHeight();
00566         adjustCenter();
00567         adjustScrollbars();
00568     }
00569     //Start the transition control timer
00570     if (!chrono.IsRunning())
00571     {
00572         chrono.Start(TIMERINTERVAL, false);
00573     }
00574     //Redraw scene
00575     drawScene();
00576 }
00577 
00578 
00580 
00585 void LayoutCanvas::drawMargins(wxDC &dc)
00586 {
00587     int widgetWidth;
00588     int widgetHeight;
00589     GetClientSize(&widgetWidth, &widgetHeight);
00590     dc.SetPen(*wxTRANSPARENT_PEN);
00591     dc.SetBrush(*wxLIGHT_GREY_BRUSH);
00592 
00593     if ((width > 0) && (height > 0))
00594     {
00595         dc.DrawRectangle(0, 0, widgetWidth, scrollY + centerY - cellSize);
00596         dc.DrawRectangle(0, 0, scrollX + centerX - cellSize, widgetHeight);
00597         dc.DrawRectangle(0, scrollY + centerY + height * cellSize + cellSize, widgetWidth, widgetHeight - (scrollY + centerY + height * cellSize + cellSize));
00598         dc.DrawRectangle(scrollX + centerX + width * cellSize + height * (cellSize/2) + cellSize, 0, widgetWidth - scrollX + centerX + width * cellSize + height * (cellSize/2), widgetHeight);
00599         dc.SetPen(*wxBLACK_PEN);
00600         dc.SetBrush(*wxTRANSPARENT_BRUSH);
00601         dc.DrawRectangle(scrollX + centerX - cellSize, scrollY + centerY - cellSize, width * cellSize + height * (cellSize/2) + cellSize*2, height * cellSize + cellSize*2);
00602     }
00603     else
00604     {
00605         dc.DrawRectangle(0, 0, widgetWidth, widgetHeight);
00606     }
00607 }
00608 
00609 
00611 
00620 void LayoutCanvas::setVisible(bool enableds, bool disableds, bool inputs, bool outputs, bool spaces)
00621 {
00622     this->enableds = enableds;
00623     this->disableds = disableds;
00624     this->inputs = inputs;
00625     this->outputs = outputs;
00626     this->spaces = spaces;
00627     drawScene();
00628 }
00629 
00630 
00632 
00640 void LayoutCanvas::setAssignedInputs(vector<coordinate> newInputs)
00641 {
00642     assignedInputs = newInputs;
00643 }
00644 
00645 
00647 
00655 void LayoutCanvas::setAssignedOutputs(vector<coordinate> newOutputs)
00656 {
00657     assignedOutputs = newOutputs;
00658 }
00659 
00660 
00662 
00665 void LayoutCanvas::drawIO(wxDC &dc)
00666 {
00667     //We draw a number in the assigned inputs/outputs.
00668     //The number is the index position of the input/output
00669     //vector.
00670     int number;
00671     
00672      if (inputs)
00673     {
00674         number = 1;
00675    
00676         for (unsigned int i = 0; i < assignedInputs.size(); i++)
00677         {
00678             if (assignedInputs[i].x >= 0)
00679             {
00680                 drawNumber(assignedInputs[i].x, assignedInputs[i].y, number, dc);
00681             }
00682             number++;
00683         }
00684     }
00685     
00686     if (outputs)
00687     {
00688         number = 1;
00689         for (unsigned int i = 0; i < assignedOutputs.size(); i++)
00690         {
00691             if (assignedOutputs[i].x >= 0)
00692             {
00693                 drawNumber(assignedOutputs[i].x, assignedOutputs[i].y, number, dc);
00694             }
00695             number++;
00696         }
00697     }
00698 }
00699 
00700 
00702 
00708 void LayoutCanvas::drawNumber(int i, int j, int number, wxDC &dc)
00709 {
00710     coordinate real;
00711     real.x = i;
00712     real.y = j;
00713     coordinate view;
00714     view = realToView(real);
00715     int w, h;
00716     dc.GetTextExtent(wxString::Format(_("%d"), number), &w, &h);
00717     dc.SetBackgroundMode(wxTRANSPARENT);
00718     dc.SetTextForeground(*wxBLACK);
00719     dc.DrawText(wxString::Format(_("%d"), number), view.x - w / 2, view.y - h / 2);
00720 }
00721 
00722 
00724 
00727 void LayoutCanvas::clear(wxDC &dc)
00728 {
00729     dc.Clear();
00730 }
00731 
00732 
00734 void LayoutCanvas::initTransitions()
00735 {
00736     transitions.resize(layout.getWidth());
00737     for (unsigned int i = 0; i < transitions.size(); i++)
00738     {
00739         transitions[i].resize(layout.getHeight());
00740         for (unsigned int j = 0; j < transitions[i].size(); j++)
00741         {
00742             transitions[i][j] = NUMTRANSITIONS -1;
00743         }
00744     }
00745 }
00746 
00747 
00749 
00754 void LayoutCanvas::OnTimer(wxTimerEvent& event)
00755 {
00756     bool stop = true;
00757     //Update the transition values
00758     for (unsigned int i = 0; i < transitions.size(); i++)
00759     {
00760         for (unsigned int j = 0; j < transitions[i].size(); j++)
00761         {
00762             if (transitions[i][j] < NUMTRANSITIONS - 1)
00763             {
00764                 transitions[i][j] = transitions[i][j] + 1;
00765                 stop = false;
00766             }
00767         }
00768     }
00769     //We stop the transition refresh if there's nothing
00770     //to be refreshed
00771     if (stop)
00772     {
00773         chrono.Stop();
00774     }
00775     //Redraw scene with the new gradient colours
00776     drawScene();
00777 }
00778 
00779 
00781 
00784 void LayoutCanvas::resetTransitions(int value)
00785 {
00786     for (unsigned int i = 0; i < transitions.size(); i++)
00787     {
00788         transitions[i].resize(layout.getHeight());
00789         for (unsigned int j = 0; j < transitions[i].size(); j++)
00790         {
00791             transitions[i][j] = value;
00792         }
00793     }
00794 }
00795 
00796 
00798 
00805 wxColour LayoutCanvas::calculateColour(wxColour initial, wxColour final, int percent)
00806 {
00807     float rIncrease;
00808     float gIncrease;
00809     float bIncrease;
00810     int r = (int)final.Red() - (int)initial.Red();
00811     rIncrease = ((float)r/NUMTRANSITIONS);
00812     r = (int)initial.Red();
00813 
00814     int g = (int)final.Green() - (int)initial.Green();
00815     gIncrease = ((float)g/NUMTRANSITIONS);
00816     g = (int)initial.Green();
00817     
00818     int b = (int)final.Blue() - (int)initial.Blue();
00819     bIncrease = ((float)b/NUMTRANSITIONS);
00820     b = (int)initial.Blue();
00821     return wxColour((unsigned char)((float)r + (float)percent*rIncrease), (unsigned char)((float)g + (float)percent*gIncrease), (unsigned char)((float)b + (float)percent*bIncrease));
00822 }

Generated on Fri Sep 1 23:55:14 2006 for NanoComp by  doxygen 1.4.6