diff --git a/src/Mod/Drawing/App/FeatureViewPart.cpp b/src/Mod/Drawing/App/FeatureViewPart.cpp index c1d7527dad86..ec100db5791f 100644 --- a/src/Mod/Drawing/App/FeatureViewPart.cpp +++ b/src/Mod/Drawing/App/FeatureViewPart.cpp @@ -194,7 +194,7 @@ App::DocumentObjectExecReturn *FeatureViewPart::execute(void) bool smooth = ShowSmoothLines.getValue(); try { - ProjectionAlgos Alg(ProjectionAlgos::invertY(shape),Dir); + ProjectionAlgos Alg(shape,Dir); result << "" << endl << output.exportEdges(H) << "" << endl; @@ -169,14 +178,15 @@ std::string ProjectionAlgos::getSVG(ExtractionType type, double scale, double to if (!HO.IsNull() && (type & WithHidden)) { double width = hiddenscale; BRepMesh::Mesh(HO,tolerance); - result << "" << endl << output.exportEdges(HO) << "" << endl; @@ -184,13 +194,14 @@ std::string ProjectionAlgos::getSVG(ExtractionType type, double scale, double to if (!VO.IsNull()) { double width = scale; BRepMesh::Mesh(VO,tolerance); - result << "" << endl << output.exportEdges(VO) << "" << endl; @@ -198,13 +209,14 @@ std::string ProjectionAlgos::getSVG(ExtractionType type, double scale, double to if (!V.IsNull()) { double width = scale; BRepMesh::Mesh(V,tolerance); - result << "" << endl << output.exportEdges(V) << "" << endl; @@ -212,13 +224,14 @@ std::string ProjectionAlgos::getSVG(ExtractionType type, double scale, double to if (!V1.IsNull() && (type & WithSmooth)) { double width = scale; BRepMesh::Mesh(V1,tolerance); - result << "" << endl << output.exportEdges(V1) << "" << endl; @@ -226,14 +239,15 @@ std::string ProjectionAlgos::getSVG(ExtractionType type, double scale, double to if (!H1.IsNull() && (type & WithSmooth) && (type & WithHidden)) { double width = hiddenscale; BRepMesh::Mesh(H1,tolerance); - result << "" << endl << output.exportEdges(H1) << "" << endl; @@ -247,7 +261,7 @@ std::string ProjectionAlgos::getDXF(ExtractionType type, double scale, double to { std::stringstream result; DXFOutput output; - + result << "0" << endl << "SECTION" << endl @@ -257,9 +271,9 @@ std::string ProjectionAlgos::getDXF(ExtractionType type, double scale, double to if (!H.IsNull() && (type & WithHidden)) { //float width = 0.15f/scale; BRepMesh::Mesh(H,tolerance); - result //<< " * + * Copyright (c) 2014 Joe Dowsett * * * * This file is part of the FreeCAD CAx development system. * * * @@ -22,814 +22,924 @@ #include "PreCompiled.h" -#ifndef _PreComp_ -# include -#endif - #include "TaskOrthoViews.h" #include "ui_TaskOrthoViews.h" #include #include #include -#include #include #include -#include -#include -#include using namespace Gui; using namespace DrawingGui; using namespace std; +#ifndef PI + #define PI 3.14159265358979323846 /* pi */ +#endif + #if 0 // needed for Qt's lupdate utility - qApp->translate("QObject", "Front"); - qApp->translate("QObject", "Back"); - qApp->translate("QObject", "Right"); - qApp->translate("QObject", "Left"); - qApp->translate("QObject", "Top"); - qApp->translate("QObject", "Bottom"); + qApp->translate("QObject", "Make axonometric..."); + qApp->translate("QObject", "Edit axonometric settings..."); + qApp->translate("QObject", "Make orthographic"); #endif -QString number_to_name(int j) + + +void pagesize(string & page_template, int dims[4], int block[4]) { - char * temp[] = {"Front","Right","Back","Left","Top","Bottom","Axonometric"}; - QString translated = QObject::tr(temp[j]); - return translated; + dims[0] = 10; // default to A4_Landscape with 10mm margins + dims[1] = 10; + dims[2] = 287; + dims[3] = 200; + + block[0] = block[1] = 0; // default to no title block + block[2] = block[3] = 0; + + int t0, t1, t2, t3 = 0; + + //code below copied from FeaturePage.cpp + Base::FileInfo fi(page_template); + if (!fi.isReadable()) + { + fi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName()); + if (!fi.isReadable()) //if so then really shouldn't have been able to get this far, but just in case... + return; + } + + // open Template file + string line; + ifstream file (fi.filePath().c_str()); + + try + { + while (!file.eof()) + { + getline (file,line); + + if (line.find("" + getline (file,line); + + if (line.find("" + + break; + } + + if (line.find("metadata") != string::npos) //give up if we meet a metadata tag + break; + } + } + catch (Standard_Failure) + { } + + file.close(); + + if (t3 != 0) + { + block[2] = t2 - t0; // block width + block[3] = t3 - t1; // block height + + if (t0 <= dims[0]) // title block on left + block[0] = -1; + else if (t2 >= dims[2]) // title block on right + block[0] = 1; + + if (t1 <= dims[1]) // title block at top + block[1] = 1; + else if (t3 >= dims[3]) // title block at bottom + block[1] = -1; + } + + dims[2] -= dims[0]; // width + dims[3] -= dims[1]; // height } -void rotate_coords(float& x, float& y, int i) + + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + + + + +orthoview::orthoview(App::Document * parent, App::DocumentObject * part, App::DocumentObject * page, Base::BoundBox3d * partbox) { - float temp[4][2] = - { - { x, y}, - {-y, x}, - {-x,-y}, - { y,-x} - }; + parent_doc = parent; + myname = parent_doc->getUniqueObjectName("Ortho"); - float t1 = temp[i][0]; - float t2 = temp[i][1]; - x = t1; - y = t2; + cx = partbox->CalcCenter().x; + cy = partbox->CalcCenter().y; + cz = partbox->CalcCenter().z; + + this_view = static_cast (parent_doc->addObject("Drawing::FeatureViewPart", myname.c_str())); + static_cast(page)->addObject(this_view); + this_view->Source.setValue(part); + + pageX = 0; + pageY = 0; + scale = 1; + + rel_x = 0; + rel_y = 0; + ortho = true; + auto_scale = true; } -void rotate_coords(int& x, int& y, int i) + +orthoview::~orthoview() { - int temp[4][2] = - { - { x, y}, - {-y, x}, - {-x,-y}, - { y,-x} - }; +} + + +void orthoview::set_data(int r_x, int r_y) +{ + rel_x = r_x; + rel_y = r_y; + + char label[15]; + sprintf(label, "Ortho_%i_%i", rel_x, rel_y); // label name for view, based on relative position - int t1 = temp[i][0]; - int t2 = temp[i][1]; - x = t1; - y = t2; + this_view->Label.setValue(label); + ortho = ((rel_x * rel_y) == 0); } -void rotate_coords(float & x, float & y, float angle) + +void orthoview::deleteme() { - float tx = x * cos(angle) - y * sin(angle); - y = x * sin(angle) + y * cos(angle); - x = tx; + parent_doc->remObject(myname.c_str()); } -float dot(float * r, float * z) + +void orthoview::setPos(float px, float py) { - return ( r[0]*z[0] + r[1]*z[1] + r[2]*z[2]); + if (px != 0 && py !=0) + { + pageX = px; + pageY = py; + } + + float ox = pageX - scale * x; + float oy = pageY + scale * y; + + this_view->X.setValue(ox); + this_view->Y.setValue(oy); } -void cross(float * r, float * n, float * p) + +void orthoview::setScale(float newScale) { - p[0] = r[1]*n[2] - r[2]*n[1]; - p[1] = r[2]*n[0] - r[0]*n[2]; - p[2] = r[0]*n[1] - r[1]*n[0]; + scale = newScale; + this_view->Scale.setValue(scale); } -void project(float * r, float * n, float * p) + +float orthoview::getScale() { - // for r projected onto plane perpendicular to n - // r x n is perpendicular to r and n (.: lies on plane) - // then n x (r x n) is perpendicular to that and to n, is the projection - float c[3]; - cross(r, n, c); - cross(n, c, p); + return scale; } -void normalise(float * r) + +void orthoview::calcCentre() { - float m = 1/sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]); - r[0] *= m; - r[1] *= m; - r[2] *= m; + x = X_dir.X() * cx + X_dir.Y() * cy + X_dir.Z() * cz; + y = Y_dir.X() * cx + Y_dir.Y() * cy + Y_dir.Z() * cz; } +void orthoview::hidden(bool state) +{ + this_view->ShowHiddenLines.setValue(state); +} + +void orthoview::smooth(bool state) +{ + this_view->ShowSmoothLines.setValue(state); +} -orthoView::orthoView(std::string name, const char * targetpage, const char * sourcepart, Base::BoundBox3d partbox) +void orthoview::set_projection(gp_Ax2 cs) { - myname = name; - mybox = partbox; + gp_Ax2 actual_cs; + gp_Dir actual_X; - orientation = 0; - angle = 0; - pageX = 0; - pageY = 0; - scale = 1; - x = 0; - y = 0; - dir = 0; - active = true; - axo = false; + // coord system & directions for desired projection + X_dir = cs.XDirection(); + Y_dir = cs.YDirection(); + Z_dir = cs.Direction(); + + // coord system of created view - same code as used in projection algos + actual_cs = gp_Ax2(gp_Pnt(0,0,0), gp_Dir(Z_dir.X(),Z_dir.Y(),Z_dir.Z())); + actual_X = actual_cs.XDirection(); - Command::doCommand(Command::Doc,"App.activeDocument().addObject('Drawing::FeatureViewPart','%s')",myname.c_str()); - Command::doCommand(Command::Doc,"App.activeDocument().%s.Source = App.activeDocument().%s",myname.c_str(), sourcepart); - Command::doCommand(Command::Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)",targetpage,myname.c_str()); - Command::doCommand(Command::Doc,"App.activeDocument().%s.Direction = (1,0,0)",myname.c_str()); + // angle between desired projection and actual projection + float rotation = X_dir.Angle(actual_X); - activate(false); + if (rotation != 0 && abs(PI - rotation) > 0.05) + if (!Z_dir.IsEqual(actual_X.Crossed(X_dir), 0.05)) + rotation = -rotation; + + calcCentre(); + + this_view->Direction.setValue(Z_dir.X(), Z_dir.Y(), Z_dir.Z()); + this_view->Rotation.setValue(180 * rotation / PI); } -orthoView::~orthoView() + + + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + + + + +OrthoViews::OrthoViews(const char * pagename, const char * partname) { + page_name = pagename; + part_name = partname; + + parent_doc = App::GetApplication().getActiveDocument(); + + part = parent_doc->getObject(partname); + bbox.Add(static_cast(part)->Shape.getBoundingBox()); + + page = parent_doc->getObject(pagename); + load_page(); + + min_space = 15; // should be preferenced + + min_r_x = max_r_x = 0; + min_r_y = max_r_y = 0; + + rotate_coeff = 1; + smooth = false; + hidden = false; + autodims = true; } -void orthoView::deleteme() +OrthoViews::~OrthoViews() { - Command::doCommand(Command::Doc,"App.activeDocument().removeObject('%s')", myname.c_str()); + for (int i = views.size() - 1; i >= 0; i--) + delete views[i]; + + page->recompute(); } -void orthoView::activate(bool state) +void OrthoViews::load_page() { - if (state) + string template_name = static_cast(page)->Template.getValue(); + pagesize(template_name, large, block); + page_dims = large; + + // process page dims for title block data + if (block[0] != 0) { - active = true; - Command::doCommand(Command::Doc,"Gui.ActiveDocument.getObject('%s').Visibility = True", myname.c_str()); - //Visibility doesn't seem to work, workaround (to counter any problems caused by active = false workaround): - //setPos(); + title = true; + + // max vertical space avoiding title block + small_v[1] = large[1]; // y margin same as large page + small_v[3] = large[3]; // y size same as large page + small_v[2] = large[2] - block[2]; // x width same as large width - block width + if (block[0] == -1) + { + small_v[0] = large[0] + block[2]; // x margin same as large + block width + horiz = &min_r_x; + } + else + { + small_v[0] = large[0]; // x margin same as large + horiz = &max_r_x; + } + + // max horizontal space avoiding title block + small_h[0] = large[0]; + small_h[2] = large[2]; + small_h[3] = large[3] - block[3]; + if (block[1] == 1) + { + small_h[1] = large[1] + block[3]; + vert = &max_r_y; + } + else + { + small_h[1] = large[1]; + vert = &min_r_y; + } } else - { - active = false; - Command::doCommand(Command::Doc,"Gui.ActiveDocument.getObject('%s').Visibility = False", myname.c_str()); - //Visibility doesn't seem to work, workaround: - Command::doCommand(Command::Doc,"App.activeDocument().%s.X = -10000", myname.c_str()); - Command::doCommand(Command::Doc,"App.activeDocument().%s.Y = -10000", myname.c_str()); - dir = 0; - width = 0; - height = 0; - } + title = false; } -void orthoView::setDir(int i) +void OrthoViews::calc_layout_size() // calculate the real world size of given view layout, assuming no space { - axo = false; - dir = i; - int vx = (dir == 1) - (dir == 3); - int vy = (dir == 0) - (dir == 2); - int vz = (dir == 4) - (dir == 5); + // note that views in relative positions x = -4, -2, 0 , 2 etc etc + // have width = orientated part width + // while those in relative positions x = -3, -1, 1 etc + // have width = orientated part depth - //drawings default to funny orientations for each view, line below calculates rotation to correct this - //drawing will then be oriented correctly for it being primary view, setOrientation is used to modify this for secondary views. - angle = -90*vx - 90*vy + (vz == -1)*180; + // similarly in y positions, height = part height or depth + + layout_width = (1 + floor(max_r_x / 2.0) + floor(-min_r_x / 2.0)) * width; + layout_width += (ceil(max_r_x / 2.0) + ceil(-min_r_x / 2.0)) * depth; + layout_height = (1 + floor(max_r_y / 2.0) + floor(-min_r_y / 2.0)) * height; + layout_height += (ceil(max_r_y / 2.0) + ceil(-min_r_y / 2.0)) * depth; +} - calcCentre(); - if (active) +void OrthoViews::choose_page() // chooses which bit of page space to use depending upon layout & titleblock +{ + int h = abs(*horiz); // how many views in direction of title block (horiz points to min_r_x or max_r_x) + int v = abs(*vert); + float layout_corner_width = (1 + floor(h / 2.0)) * width + ceil(h / 2.0) * depth; // from (0, 0) view inclusively, how wide and tall is the layout in the direction of the title block + float layout_corner_height = (1 + floor(v / 2.0)) * height + ceil(v / 2.0) * depth; + float rel_space_x = layout_corner_width / layout_width - 1.0 * block[2] / large[2]; // relative to respective sizes, how much space between (0, 0) and title block, + float rel_space_y = layout_corner_height / layout_height - 1.0 * block[3] / large[3]; // can be -ve if block extends into / beyond (0, 0) view + float view_x, view_y, v_x_r, v_y_r; + bool interferes = false; + float a, b; + + for (int i = min_r_x; i <= max_r_x; i++) + for (int j = min_r_y; j <= max_r_y; j++) + if (index(i, j) != -1) // is there a view in this position? + { + a = i * block[0] * 0.5; // reflect i and j so as +ve is in direction of title block ## + b = j * block[1] * 0.5; + view_x = ceil(a + 0.5) * width + ceil(a) * depth; // extreme coords of view in direction of block, measured from far corner of (0, 0) view, + view_y = ceil(b + 0.5) * height + ceil(b) * depth; // can be -ve if view is on opposite side of (0, 0) from title block + v_x_r = view_x / layout_width; // make relative + v_y_r = view_y / layout_height; + if (v_x_r > rel_space_x && v_y_r > rel_space_y) // ## so that can use > in this condition regardless of position of block + interferes = true; + } + + if (!interferes) + page_dims = large; + else { - Command::doCommand(Command::Doc,"App.activeDocument().%s.Direction = (%d,%d,%d)",myname.c_str(),vx,vy,vz); - Command::doCommand(Command::Doc,"App.activeDocument().%s.Label = '%s'",myname.c_str(),(const char*)number_to_name(i).toUtf8()); + if (min(small_h[2] / layout_width, small_h[3] / layout_height) > min(small_v[2] / layout_width, small_v[3] / layout_height)) + page_dims = small_h; + else + page_dims = small_v; } } -void orthoView::setDir(float vx, float vy, float vz, float ang, int vert_index) +void OrthoViews::calc_scale() // compute scale required to meet minimum space requirements { - //calcCentre(); - vert[0] = 0; - vert[1] = 0; - vert[2] = 0; + float scale_x, scale_y, working_scale; - switch(vert_index) - { - case 0: - vert[1] = -1; - break; - case 1: - vert[0] = 1; - break; - case 2: - vert[1] = 1; - break; - case 3: - vert[0] = -1; - break; - case 4: - vert[2] = 1; - break; - case 5: - vert[2] = -1; - } + scale_x = (page_dims[2] - num_gaps_x * min_space) / layout_width; + scale_y = (page_dims[3] - num_gaps_y * min_space) / layout_height; - axo = true; - n[0] = vx; - n[1] = vy; - n[2] = vz; - angle = ang; - setOrientation(0); + working_scale = min(scale_x, scale_y); - if (active) - { - Command::doCommand(Command::Doc,"App.activeDocument().%s.Direction = (%f,%f,%f)",myname.c_str(),vx,vy,vz); - Command::doCommand(Command::Doc,"App.activeDocument().%s.Label = '%s'",myname.c_str(),number_to_name(6).toStdString().c_str()); - } + //which gives the largest scale for which the min_space requirements can be met, but we want a 'sensible' scale, rather than 0.28457239... + //eg if working_scale = 0.115, then we want to use 0.1, similarly 7.65 -> 5, and 76.5 -> 50 + + float exponent = floor(log10(working_scale)); //if working_scale = a * 10^b, what is b? + working_scale *= pow(10, -exponent); //now find what 'a' is. + + float valid_scales[2][8] = {{1, 1.25, 2, 2.5, 3.75, 5, 7.5, 10}, //equate to 1:10, 1:8, 1:5, 1:4, 3:8, 1:2, 3:4, 1:1 + {1, 1.5, 2, 3, 4, 5, 8, 10}}; //equate to 1:1, 3:2, 2:1, 3:1, 4:1, 5:1, 8:1, 10:1 + + int i = 7; + while (valid_scales[(exponent>=0)][i] > working_scale) //choose closest value smaller than 'a' from list. + i -= 1; //choosing top list if exponent -ve, bottom list for +ve exponent + + scale = valid_scales[(exponent>=0)][i] * pow(10, exponent); //now have the appropriate scale, reapply the *10^b } -void orthoView::setPos(float px, float py) +void OrthoViews::calc_offsets() // calcs SVG coords for centre of upper left view { - if (px != 0 && py !=0) + // space_x is the emptry clear white space between views + // gap_x is the centre - centre distance between views + + float space_x = (page_dims[2] - scale * layout_width) / num_gaps_x; + float space_y = (page_dims[3] - scale * layout_height) / num_gaps_y; + + gap_x = space_x + scale * (width + depth) * 0.5; + gap_y = space_y + scale * (height + depth) * 0.5; + + if (min_r_x % 2 == 0) + offset_x = page_dims[0] + space_x + 0.5 * scale * width; + else + offset_x = page_dims[0] + space_x + 0.5 * scale * depth; + + if (max_r_y % 2 == 0) + offset_y = page_dims[1] + space_y + 0.5 * scale * height; + else + offset_y = page_dims[1] + space_y + 0.5 * scale * depth; +} + + +void OrthoViews::set_views() // process all views - scale & positions +{ + float x; + float y; + + for (unsigned int i = 0; i < views.size(); i++) { - pageX = px; - pageY = py; + x = offset_x + (views[i]->rel_x - min_r_x) * gap_x; + y = offset_y + (max_r_y - views[i]->rel_y) * gap_y; + + if (views[i]->auto_scale) + views[i]->setScale(scale); + + views[i]->setPos(x, y); } +} - float ox = pageX + x; - float oy = pageY + y; - if (active) +void OrthoViews::process_views() // update scale and positions of views +{ + if (autodims) { - Command::doCommand(Command::Doc,"App.activeDocument().%s.X = %f", myname.c_str(), ox); - Command::doCommand(Command::Doc,"App.activeDocument().%s.Y = %f", myname.c_str(), oy); + calc_layout_size(); + + if (title) + choose_page(); + + calc_scale(); + calc_offsets(); } + + set_views(); + parent_doc->recompute(); } -void orthoView::setScale(float newScale) +void OrthoViews::set_hidden(bool state) { - scale = newScale; - if (active) - Command::doCommand(Command::Doc,"App.activeDocument().%s.Scale = %f",myname.c_str(), scale); - calcCentre(); + hidden = state; + + for (unsigned int i = 0; i < views.size(); i++) + views[i]->hidden(hidden); + + parent_doc->recompute(); } -void orthoView::setOrientation(int orient) +void OrthoViews::set_smooth(bool state) { - orientation = orient; - if (active) - Command::doCommand(Command::Doc,"App.activeDocument().%s.Rotation = %f", myname.c_str(), (90*orientation+angle)); - calcCentre(); + smooth = state; + + for (unsigned int i = 0; i < views.size(); i++) + views[i]->smooth(smooth); + + parent_doc->recompute(); } -void orthoView::calcCentre() +void OrthoViews::set_primary(gp_Dir facing, gp_Dir right) // set the orientation of the primary view { -//the drawing view 'Position' refers to where the part origin should be on the page -//we need to find the position of the centre of correct bounding box face relative to the part origin -//this depends upon: -// - which view (eg Front, Left, Top etc), given by 'dir' -// - the scale of the drawing, since eg centre.x is the absolute point, while x is the distance on page. -// - the orientation of the view on the page, will switch x/y as per a rotation. + primary.SetDirection(facing); + primary.SetXDirection(right); + gp_Dir up = primary.YDirection(); - float cx = mybox.CalcCenter().x; - float cy = mybox.CalcCenter().y; - float cz = mybox.CalcCenter().z; + // compute dimensions of part when orientated according to primary view + width = abs(right.X() * bbox.LengthX() + right.Y() * bbox.LengthY() + right.Z() * bbox.LengthZ()); + height = abs(up.X() * bbox.LengthX() + up.Y() * bbox.LengthY() + up.Z() * bbox.LengthZ()); + depth = abs(facing.X() * bbox.LengthX() + facing.Y() * bbox.LengthY() + facing.Z() * bbox.LengthZ()); - if (axo) + if (views.size() == 0) + add_view(0, 0); + else { - float p[3] = {cx, -cy, cz}; - float n_p[3] = {n[0], -n[1], n[2]}; - float proj_p[3]; - float proj_y[3]; // will be the y axis of the projection - float proj_x[3]; // will be the x axis of the projection - - project(vert, n_p, proj_y); - //project(p, n, proj_p); - cross(proj_y, n_p, proj_x); - normalise(proj_x); - normalise(proj_y); - x = -scale * dot(p, proj_x); - y = scale * dot(p, proj_y); - //rotate_coords(x, y, angle) + views[0]->set_projection(primary); + set_all_orientations(); // reorient all other views appropriately + process_views(); } - else +} + + +void OrthoViews::set_orientation(int index) // set orientation of single view +{ + double rotation; + int n; // how many 90* rotations from primary view? + gp_Dir dir; // rotate about primary x axis (if in a relative y position) or y axis? + gp_Ax2 cs; + + if (views[index]->ortho) { - float coords[6][2] = + if (views[index]->rel_x != 0) { - {-cx, cz}, //front - { cy, cz}, //right - { cx, cz}, //back - {-cy, cz}, //left - {-cx, -cy}, //top - {-cx, cy} //bottom - }; - - x = coords[dir][0] * scale; - y = coords[dir][1] * scale; - rotate_coords(x,y,orientation); - - float dx = mybox.LengthX(); - float dy = mybox.LengthY(); - float dz = mybox.LengthZ(); - - float dims[6][2] = - { - {dx, dz}, //front - {dy, dz}, //right - {dx, dz}, //back - {dy, dz}, //left - {dx, dy}, //top - {dx, dy} //bottom - }; - - width = dims[dir][0]; - height = dims[dir][1]; - if (orientation % 2 == 1) + dir = primary.YDirection(); + n = views[index]->rel_x; + } + else { - float temp = width; - width = height; - height = temp; + dir = primary.XDirection(); + n = -views[index]->rel_y; } + + rotation = n * rotate_coeff * PI/2; // rotate_coeff is -1 or 1 for 1st or 3rd angle + cs = primary.Rotated(gp_Ax1(gp_Pnt(0,0,0), dir), rotation); + views[index]->set_projection(cs); } } -void orthoView::hidden(int state) +void OrthoViews::set_all_orientations() // set orientations of all views (ie projection or primary changed) { - if (state == 2) - Command::doCommand(Command::Doc,"App.activeDocument().%s.ShowHiddenLines = True", myname.c_str()); - else - Command::doCommand(Command::Doc,"App.activeDocument().%s.ShowHiddenLines = False", myname.c_str()); + for (unsigned int i = 1; i < views.size(); i++) // start from 1 - the 0 is the primary view + { + if (views[i]->ortho) + set_orientation(i); + else + set_Axo(views[i]->rel_x, views[i]->rel_y); + } } -void orthoView::smooth(int state) +void OrthoViews::set_projection(int proj) // 1 = 1st angle, 3 = 3rd angle { - if (state == 2) - Command::doCommand(Command::Doc,"App.activeDocument().%s.ShowSmoothLines = True", myname.c_str()); - else - Command::doCommand(Command::Doc,"App.activeDocument().%s.ShowSmoothLines = False", myname.c_str()); -} + if (proj == 3) + rotate_coeff = 1; + else if (proj == 1) + rotate_coeff = -1; -/////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////// + set_all_orientations(); + process_views(); +} -TaskOrthoViews::TaskOrthoViews(QWidget *parent) - : ui(new Ui_TaskOrthoViews) +void OrthoViews::add_view(int rel_x, int rel_y) // add a new view to the layout { - ui->setupUi(this); + if (index(rel_x, rel_y) == -1) + { + orthoview * view = new orthoview(parent_doc, part, page, & bbox); + view->set_data(rel_x, rel_y); + views.push_back(view); - std::vector obj = Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId()); - Base::BoundBox3d bbox; - std::vector::iterator it = obj.begin(); - bbox.Add(static_cast(*it)->Shape.getBoundingBox()); + max_r_x = max(max_r_x, rel_x); + min_r_x = min(min_r_x, rel_x); + max_r_y = max(max_r_y, rel_y); + min_r_y = min(min_r_y, rel_y); - const char * part = obj.front()->getNameInDocument(); - App::Document* doc = App::GetApplication().getActiveDocument(); + num_gaps_x = max_r_x - min_r_x + 2; + num_gaps_y = max_r_y - min_r_y + 2; - std::vector pages = doc->getObjectsOfType(Drawing::FeaturePage::getClassTypeId()); - std::string PageName = pages.front()->getNameInDocument(); - const char * page = PageName.c_str(); + int i = views.size() - 1; + views[i]->hidden(hidden); + views[i]->smooth(smooth); - App::DocumentObject * this_page = doc->getObject(page); - std::string template_name = static_cast(this_page)->Template.getValue(); + if (views[i]->ortho) + set_orientation(i); + else + set_Axo(rel_x, rel_y); - std::string name1 = doc->getUniqueObjectName("Ortho").c_str(); - views[0] = new orthoView(name1, page, part, bbox); - name1 = doc->getUniqueObjectName("Ortho").c_str(); - views[1] = new orthoView(name1, page, part, bbox); - name1 = doc->getUniqueObjectName("Ortho").c_str(); - views[2] = new orthoView(name1, page, part, bbox); - name1 = doc->getUniqueObjectName("Ortho").c_str(); - views[3] = new orthoView(name1, page, part, bbox); + process_views(); + } +} - margin = 10; - pagesize(template_name); - min_space = 15; - // [x+2][y+2] - c_boxes[0][2] = ui->cb02; //left most, x = -2, y = 0 - c_boxes[1][1] = ui->cb11; - c_boxes[1][2] = ui->cb12; - c_boxes[1][3] = ui->cb13; - c_boxes[2][0] = ui->cb20; //top most, x = 0, y = -2 - c_boxes[2][1] = ui->cb21; - c_boxes[2][2] = ui->cb22; //centre (primary view) checkbox x = y = 0. - c_boxes[2][3] = ui->cb23; - c_boxes[2][4] = ui->cb24; //bottom most, x = 0, y = 2 - c_boxes[3][1] = ui->cb31; - c_boxes[3][2] = ui->cb32; - c_boxes[3][3] = ui->cb33; - c_boxes[4][2] = ui->cb42; //right most, x = 2, y = 0 - - for (int i=0; i < 5; i++) - for (int j=0; j < 5; j++) - if ((abs(i-2) + abs(j-2)) < 3) //if i,j combination corresponds to valid check box, then proceed with: - connect(c_boxes[i][j], SIGNAL(toggled(bool)), this, SLOT(cb_toggled(bool))); +void OrthoViews::del_view(int rel_x, int rel_y) // remove a view from the layout +{ + int num = index(rel_x, rel_y); - inputs[0] = ui->scale_0; - inputs[1] = ui->x_1; - inputs[2] = ui->y_2; - inputs[3] = ui->spacing_h_3; - inputs[4] = ui->spacing_v_4; - ui->tabWidget->setTabEnabled(1,false); + if (num > 0) + { + views[num]->deleteme(); + delete views[num]; + views.erase(views.begin() + num); - for (int i=0; i < 5; i++) - connect(inputs[i], SIGNAL(editingFinished()), this, SLOT(data_entered())); + min_r_x = max_r_x = 0; + min_r_y = max_r_y = 0; - connect(ui->projection, SIGNAL(currentIndexChanged(int)), this, SLOT(projectionChanged(int))); - connect(ui->rotate, SIGNAL(currentIndexChanged(int)), this, SLOT(setRotate(int))); - connect(ui->smooth, SIGNAL(stateChanged(int)), this, SLOT(smooth(int))); - connect(ui->hidden, SIGNAL(stateChanged(int)), this, SLOT(hidden(int))); - connect(ui->auto_tog, SIGNAL(stateChanged(int)), this, SLOT(toggle_auto(int))); - connect(ui->primary, SIGNAL(activated(int)), this, SLOT(setPrimary(int))); - - connect(ui->axoProj, SIGNAL(activated(int)), this, SLOT(axoChanged(int))); - connect(ui->axoTop, SIGNAL(activated(int)), this, SLOT(axoTopChanged(int))); - connect(ui->axoLeft, SIGNAL(activated(int)), this, SLOT(axoChanged(int))); - connect(ui->flip, SIGNAL(clicked()), this, SLOT(axo_flip())); - connect(ui->axoScale, SIGNAL(editingFinished()), this, SLOT(axoScale())); - - //these matrices contain information relating relative position on page to which view appears there, and in which orientation - - //first matrix is for front, right, back, left. Only needs to contain positions above and below primary since in positions horizontally - //displaced, the view appearing there is simply found from the same f, r, b, l sequence. - //thus [i][j][k], i values are which primary view (0-3), j is vertical displacement corresponding to (-2/+2, -1, 1) - //then in k = 0 is the view number, k = 1 is the orientation (*90 clockwise) - - //second matrix is for primaries top (4), i=0 gives horizontal positions, i = 1 vertical ones - //and bottom (5) i = 2 (horiz) and 3 (vert). - //then j and k values as for first matrix. - - int temp1[4][3][2] = {{{2,2}, {4,0}, {5,0}}, //primary 0, secondary {direction, rotation} in y = -2, -1, 1 positions - {{3,2}, {4,1}, {5,3}}, //primary 1, secondaries in y = 2 position duplicate y = -2 - {{0,2}, {4,2}, {5,2}}, //primary 2, secondaries in horizontal positions x = -2, -1, 1, 2 - {{1,2}, {4,3}, {5,1}}}; //primary 3, given by linear position from primary = (p + x) mod 4 - - int temp2[4][3][2] = {{{5,2}, {3,1}, {1,3}}, //primary 4, secondaries in horizontal x = -2, -1, 1 (x = 2 duplicates x = -2) - {{5,0}, {2,2}, {0,0}}, //primary 4, vertical positions - {{4,2}, {3,3}, {1,1}}, //primary 5, horizontal - {{4,0}, {0,0}, {2,2}}}; //primary 5, vertical - - for (int i=0; i < 4; i++) - for (int j=0; j < 3; j++) - for (int k=0; k < 2; k++) //initialisation needs to be done this way (rather than initialise maps directly - { - map1[i][j][k] = temp1[i][j][k]; //in order to avoid compiler warning - map2[i][j][k] = temp2[i][j][k]; - } + for (unsigned int i = 1; i < views.size(); i++) // start from 1 - the 0 is the primary view + { + min_r_x = min(min_r_x, views[i]->rel_x); // calculate extremes from remaining views + max_r_x = max(max_r_x, views[i]->rel_x); + min_r_y = min(min_r_y, views[i]->rel_y); + max_r_y = max(max_r_y, views[i]->rel_y); + } - float temp[3][6][4][4] = - // isometric - {{{{1,1,1,180},{-1,1,-1,180},{-1,1,1,180},{1,1,-1,180}}, // top face is the Right - {{1,1,-1,60},{1,-1,1,240},{1,1,1,300},{1,-1,-1,120}}, // Front - {{1,-1,-1,0},{-1,-1,1,0},{1,-1,1,0},{-1,-1,-1,0}}, // Left - {{-1,1,1,60},{-1,-1,-1,240},{-1,-1,1,120},{-1,1,-1,300}}, // Back - {{1,1,1,60},{1,-1,1,120},{-1,-1,1,240},{-1,1,1,300}}, // Top - {{-1,1,-1,60},{1,1,-1,300},{1,-1,-1,240},{-1,-1,-1,120}}}, // Bottom - - // dimetric - {{{0.681,0.267,0.681,180},{-0.681,0.267,-0.681,180},{-0.681,0.267,0.681,180},{0.681,0.267,-0.681,180}}, // top face is the Right - {{0.267,0.681,-0.681,0},{0.267,-0.681,0.681,0},{0.267,0.681,0.681,0},{0.267,-0.681,-0.681,0}}, // Front - {{0.681,-0.267,-0.681,0},{-0.681,-0.267,0.681,0},{0.681,-0.267,0.681,0},{-0.681,-0.267,-0.681,0}}, // Left - {{-0.267,0.681,0.681,180},{-0.267,-0.681,-0.681,180},{-0.267,-0.681,0.681,180},{-0.267,0.681,-0.681,180}}, // Back - {{0.681,0.681,0.267,0},{0.681,-0.681,0.267,0},{-0.681,-0.681,0.267,0},{-0.681,0.681,0.267,0}}, // Top - {{-0.681,0.681,-0.267,180},{0.681,0.681,-0.267,180},{0.681,-0.681,-0.267,180},{-0.681,-0.681,-0.267,180}}}, // Bottom - - // trimetric - {{{0.211,0.577,0.788,-98.8},{-0.211,0.577,-0.788,81.2},{-0.788,0.577,0.211,81.2},{0.788,0.577,-0.211,-98.8}}, // top face is the Right - {{0.577,0.211,-0.788,81.2},{0.577,-0.211,0.788,-98.8},{0.577,0.788,0.211,-98.8},{0.577,-0.788,-0.211,81.2}}, // Front - {{0.211,-0.577,-0.788,-98.8},{-0.211,-0.577,0.788,81.2},{0.788,-0.577,0.211,81.2},{-0.788,-0.577,-0.211,-98.8}}, // Left - {{-0.577,0.211,0.788,81.2},{-0.577,-0.211,-0.788,-98.8},{-0.577,-0.788,0.211,-98.8},{-0.577,0.788,-0.211,81.2}}, // Back - {{0.788,0.211,0.577,-98.8},{0.211,-0.788,0.577,81.2},{-0.788,-0.211,0.577,81.2},{-0.211,0.788,0.577,-98.8}}, // Top - {{-0.788,0.211,-0.577,-98.8},{0.211,0.788,-0.577,81.2},{0.788,-0.211,-0.577,81.2},{-0.211,-0.788,-0.577,-98.8}}}}; // Bottom - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 6; j++) - for (int k = 0; k < 4; k++) - for (int l = 0; l < 4; l++) - axonometric[i][j][k][l] = temp[i][j][k][l]; - - //initialise variables - - for (int i=0; i < 4; i++) - for (int j=0; j < 4; j++) - view_status[i][j] = 0; - - view_count = 0; - primary = 0; - rotate = 0; - proj = 1; - autoscale = 1; - axo_flipped = false; - - //below are calculated in case autodims is deselected before these values are initialised. - float max_dim = max(max(bbox.LengthX(), bbox.LengthY()), bbox.LengthZ()); - scale = min(pagewidth, pageheight)/(4*max_dim+5*min_space); - horiz = scale*max_dim + min_space; - vert = horiz; - x_pos = pagewidth/2; - y_pos = pageheight/2; - - data[0] = &scale; - data[1] = &x_pos; - data[2] = &y_pos; - data[3] = &horiz; - data[4] = | - - -// Command::doCommand(Command::Doc,"#%d", map1[2][2][1]); + num_gaps_x = max_r_x - min_r_x + 2; + num_gaps_y = max_r_y - min_r_y + 2; -} //end of constructor + process_views(); + } +} -TaskOrthoViews::~TaskOrthoViews() +void OrthoViews::del_all() { - delete views[0]; - delete views[1]; - delete views[2]; - delete views[3]; - delete ui; + for (int i = views.size() - 1; i >= 0; i--) // count downwards to delete from back + { + views[i]->deleteme(); + delete views[i]; + views.pop_back(); + } } -void TaskOrthoViews::changeEvent(QEvent *e) +int OrthoViews::is_Ortho(int rel_x, int rel_y) // is the view at r_x, r_y an ortho or axo one? { - if (e->type() == QEvent::LanguageChange) { - ui->retranslateUi(this); - } + int result = index(rel_x, rel_y); + + if (result != -1) + result = views[result]->ortho; + + return result; } -void TaskOrthoViews::pagesize(std::string& page_template) +int OrthoViews::index(int rel_x, int rel_y) // index in vector of view, -1 if doesn't exist { - // /********update num_templates when adding extra templates*******************/ + int index = -1; - const int num_templates = 2; - std::string templates[num_templates] = {"A3_Landscape.svg", "A4_Landscape.svg"}; - int dimensions[num_templates][3] = {{420,297,227},{297,210,153}}; //{width, full height, reduced height} measured from page edge. - - for (int i=0; i < num_templates; i++) - { -// if (templates[i] == page_template) - if (page_template.find(templates[i]) != std::string::npos) + for (unsigned int i = 0; i < views.size(); i++) + if (views[i]->rel_x == rel_x && views[i]->rel_y == rel_y) { - pagewidth = dimensions[i][0] - 2*margin; - pageh1 = dimensions[i][1] - 2*margin; - pageh2 = dimensions[i][2] - margin; - return; + index = i; + break; } + + return index; +} + + +void OrthoViews::set_Axo_scale(int rel_x, int rel_y, float axo_scale) // set an axo scale independent of ortho ones +{ + int num = index(rel_x, rel_y); + + if (num != -1 && !views[num]->ortho) + { + views[num]->auto_scale = false; + views[num]->setScale(axo_scale); + views[num]->setPos(); + parent_doc->recompute(); } +} - //matching template not found, read through template file for width & height info. - //code below copied from FeaturePage.cpp - Base::FileInfo fi(page_template); - if (!fi.isReadable()) +void OrthoViews::set_Axo(int rel_x, int rel_y, gp_Dir up, gp_Dir right, bool away, int axo, bool tri) // set custom axonometric view +{ + int num = index(rel_x, rel_y); + double rotations[2]; + gp_Dir dir; + + views[num]->ortho = false; + views[num]->away = away; + views[num]->tri = tri; + views[num]->axo = axo; + + if (axo == 0) { - fi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName()); - if (!fi.isReadable()) //if so then really shouldn't have been able to get this far, but just in case... - { - pagewidth = 277; - pageh1 = 190; - pageh2 = 190; - return; - } + rotations[0] = -0.7853981633974476; + rotations[1] = -0.6154797086703873; + } + else if (axo == 1) + { + rotations[0] = -0.7853981633974476; + rotations[1] = -0.2712637537260206; + } + else if (tri) + { + rotations[0] = -1.3088876392502007; + rotations[1] = -0.6156624905260762; + } + else + { + rotations[0] = 1.3088876392502007 - PI/2; + rotations[1] = -0.6156624905260762; } - // open Template file - std::string line; - std::string temp_line; - std::ifstream file (fi.filePath().c_str()); - size_t found; - bool done = false; + if (away) + rotations[1] = - rotations[1]; - try + gp_Ax2 cs = gp_Ax2(gp_Pnt(0,0,0), right); + cs.SetYDirection(up); + cs.Rotate(gp_Ax1(gp_Pnt(0,0,0), up), rotations[0]); + dir = cs.XDirection(); + cs.Rotate(gp_Ax1(gp_Pnt(0,0,0), dir), rotations[1]); + + views[num]->up = up; + views[num]->right = right; + views[num]->set_projection(cs); + views[num]->setPos(); + + parent_doc->recompute(); +} + + +void OrthoViews::set_Axo(int rel_x, int rel_y) // set view to default axo projection +{ + int num = index(rel_x, rel_y); + + if (num != -1) { - while (!file.eof()) + gp_Dir up = primary.YDirection(); // default to view from up and right + gp_Dir right = primary.XDirection(); + bool away = false; + + if (rel_x * rel_y != 0) // but change default if it's a diagonal position { - getline (file,line); - found = line.find("width="); - if (found != std::string::npos) + if (rotate_coeff == 1) // third angle { - temp_line = line.substr(7+found); - sscanf (temp_line.c_str(), "%f", &pagewidth); - pagewidth -= 2*margin; + away = (rel_y < 0); - if (done) - { - file.close(); - return; - } + if (rel_x < 0) + right = primary.Direction(); else - done = true; + right = primary.XDirection(); } - - found = line.find("height="); - if (found != std::string::npos) + else // first angle { - temp_line = line.substr(8+found); - sscanf (temp_line.c_str(), "%f", &pageh1); - pageh1 -= 2*margin; - pageh2 = pageh1; + away = (rel_y > 0); - if (done) - { - file.close(); - return; - } + if (rel_x > 0) + right = primary.Direction(); else - done = true; + right = primary.XDirection(); } - - if (line.find("metadata") != std::string::npos) //give up if we meet a metadata tag - break; } + set_Axo(rel_x, rel_y, up, right, away); } - catch (Standard_Failure) - { } - - file.close(); - - //width/height not found?? fallback to A4 landscape simple: - pagewidth = 277; - pageh1 = 190; - pageh2 = 190; } -void TaskOrthoViews::autodims() +void OrthoViews::set_Ortho(int rel_x, int rel_y) // return view to orthographic { - /************************************* calculate real size of views in layout *****************/ - - float w1 = 0, w2 = 0, h1 = 0, h2 = 0; - int min_x = 0, min_y = 0; - int max_x = 0, max_y = 0; + int num = index(rel_x, rel_y); - w1 = views[0]->width; //w1,h1 are width/height of primary view - h1 = views[0]->height; //w2 width of first view left/right of primary, h2 height of first view up/down - - for (int i = 0; i < 4; i++) + if (num != -1 && rel_x * rel_y == 0) { - min_x = min(min_x, view_status[i][2]); - min_y = min(min_y, view_status[i][3]); - max_x = max(max_x, view_status[i][2]); - max_y = max(max_y, view_status[i][3]); - - if (abs(view_status[i][2]) == 1 && abs(view_status[i][3]) == 0) - w2 = views[i]->width; - else if (abs(view_status[i][2]) == 0 && abs(view_status[i][3]) == 1) - h2 = views[i]->height; + views[num]->ortho = true; + views[num]->setScale(scale); + views[num]->auto_scale = true; + set_orientation(num); + views[num]->setPos(); + + parent_doc->recompute(); } +} + - float width = (min_x == -2)*w1 + (min_x < 0)*w2 + w1 + (max_x > 0)*w2 + (max_x == 2) * w1; - float height = (min_y == -2)*h1 + (min_y < 0)*h2 + h1 + (max_y > 0)*h2 + (max_y == 2) * h1; - int wide = max_x - min_x + 1; //how many views wide / high? - int high = max_y - min_y + 1; +bool OrthoViews::get_Axo(int rel_x, int rel_y, int & axo, gp_Dir & up, gp_Dir & right, bool & away, bool & tri, float & axo_scale) +{ + int num = index(rel_x, rel_y); - if (max_y > 0 && !c_boxes[3][3]->isChecked() && min_x == 0 && ((max_x == 1)*w2 > w1 || max_x == 2)) - pageheight = pageh1; + if (num != -1 && !views[num]->ortho) + { + axo = views[num]->axo; + up = views[num]->up; + right = views[num]->right; + away = views[num]->away; + tri = views[num]->tri; + axo_scale = views[num]->getScale(); + return true; + } else - pageheight = pageh2; + return false; +} - /*************************************** calculate scale **************************************/ - float working_scale = min((pagewidth - (wide + 1) * min_space) / width, (pageheight - (high + 1) * min_space) / height); +void OrthoViews::auto_dims(bool setting) +{ + autodims = setting; + if (autodims) + process_views(); +} - //which gives the largest scale for which the min_space requirements can be met, but we want a 'sensible' scale, rather than 0.28457239... - //eg if working_scale = 0.115, then we want to use 0.1, similarly 7.65 -> 5, and 76.5 -> 50 - float exponent = floor(log10(working_scale)); //if working_scale = a * 10^b, what is b? - working_scale *= pow(10, -exponent); //now find what 'a' is. +void OrthoViews::set_configs(float configs[5]) // for autodims off, set scale & positionings +{ + if (!autodims) + { + scale = configs[0]; + offset_x = configs[1]; + offset_y = configs[2]; + gap_x = configs[3]; + gap_y = configs[4]; + process_views(); + } +} - float valid_scales[2][8] = {{1, 1.25, 2, 2.5, 3.75, 5, 7.5, 10}, //equate to 1:10, 1:8, 1:5, 1:4, 3:8, 1:2, 3:4, 1:1 - {1, 1.5, 2, 3, 4, 5, 8, 10}}; //equate to 1:1, 3:2, 2:1, 3:1, 4:1, 5:1, 8:1, 10:1 - int i = 0; - while (valid_scales[(exponent>=0)][i] <= working_scale) //choose closest value smaller than 'a' from list. - i += 1; //choosing top list if exponent -ve, bottom list for +ve exponent - i -= 1; - float chosen_scale = valid_scales[(exponent>=0)][i]; - scale = chosen_scale * pow(10, exponent); //now have the appropriate scale, reapply the *10^b +void OrthoViews::get_configs(float configs[5]) // get scale & positionings +{ + configs[0] = scale; + configs[1] = offset_x; + configs[2] = offset_y; + configs[3] = gap_x; + configs[4] = gap_y; +} - /************************************* calculate position of views on page ********************/ - width *= scale; - height *= scale; - w1 *= scale; - w2 *= scale; - h1 *= scale; - h2 *= scale; - float space = min((pagewidth - width)/(wide + 1), (pageheight - height)/(high + 1)); - vert = space + (h1 + h2)/2; //centre-centre spacing of views - horiz = space + (w1 + w2)/2; +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// - float left = -min_x * horiz + (min_x == -1) * w2/2 + (min_x != -1) * w1/2; //width of layout left of primary centre - float right = max_x * horiz + (max_x == 1) * w2/2 + (max_x != 1) * w1/2; // " " right " " - float up = -min_y * vert + (min_y == -1) * h2/2 + (min_y != -1) * h1/2; - float down = max_y * vert + (max_y == 1) * h2/2 + (max_y != 1) * h1/2; - x_pos = pagewidth/2 + margin - (right-left)/2; - y_pos = pageheight/2 + margin - (down-up)/2; - x_pos = floor(x_pos * 10 + 0.5) / 10; //round to nearest tenth - y_pos = floor(y_pos * 10 + 0.5) / 10; - horiz = floor(horiz * 10 + 0.5) / 10; - vert = floor(vert * 10 + 0.5) / 10; +TaskOrthoViews::TaskOrthoViews(QWidget *parent) + : ui(new Ui_TaskOrthoViews) +{ + ui->setupUi(this); + vector obj = Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId()); + const char * part = obj.front()->getNameInDocument(); - /************************************* update gui text boxes **********************************/ + App::Document * doc = App::GetApplication().getActiveDocument(); + vector pages = doc->getObjectsOfType(Drawing::FeaturePage::getClassTypeId()); + string PageName = pages.front()->getNameInDocument(); + const char * page = PageName.c_str(); - for (int i = 0; i < 5; i++) - inputs[i]->setText(QString::number(*data[i])); -} + // ********************************************************************** + // note that checkboxes are numbered increasing right & down + // while OrthoViews relative positions are increasing right & up + // doh! I should renumber the checkboxes for clarity + // ********************************************************************** -void TaskOrthoViews::compute() -{ - float temp_scale = scale; - if (autoscale) - autodims(); + // [x+2][y+2] + c_boxes[0][2] = ui->cb02; //left most, x = -2, y = 0 + c_boxes[1][1] = ui->cb11; + c_boxes[1][2] = ui->cb12; + c_boxes[1][3] = ui->cb13; + c_boxes[2][0] = ui->cb20; //top most, x = 0, y = -2 + c_boxes[2][1] = ui->cb21; + c_boxes[2][2] = ui->cb22; //centre (primary view) checkbox x = y = 0. + c_boxes[2][3] = ui->cb23; + c_boxes[2][4] = ui->cb24; //bottom most, x = 0, y = 2 + c_boxes[3][1] = ui->cb31; + c_boxes[3][2] = ui->cb32; + c_boxes[3][3] = ui->cb33; + c_boxes[4][2] = ui->cb42; //right most, x = 2, y = 0 - for (int i = 0; i < 4; i++) - { - if (i == axo && i > 0) - { - if (temp_scale == ui->axoScale->text().toFloat()) + for (int i=0; i < 5; i++) + for (int j=0; j < 5; j++) + if ((abs(i-2) + abs(j-2)) < 3) //if i,j combination corresponds to valid check box, then proceed with: { - views[i]->setScale(scale); // only update the axonometric scale if it wasn't manually changed - ui->axoScale->setText(QString::number(scale)); + connect(c_boxes[i][j], SIGNAL(toggled(bool)), this, SLOT(cb_toggled(bool))); + connect(c_boxes[i][j], SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(ShowContextMenu(const QPoint&))); } - } - else - views[i]->setScale(scale); - views[i]->setPos(x_pos + view_status[i][2] * horiz, y_pos + view_status[i][3] * vert); + // access scale / position QLineEdits via array + inputs[0] = ui->scale_0; + inputs[1] = ui->x_1; + inputs[2] = ui->y_2; + inputs[3] = ui->spacing_h_3; + inputs[4] = ui->spacing_v_4; + + for (int i=0; i < 5; i++) + { + connect(inputs[i], SIGNAL(textEdited(const QString &)), this, SLOT(data_entered(const QString &))); + connect(inputs[i], SIGNAL(returnPressed()), this, SLOT(text_return())); } - Command::updateActive(); - Command::commitCommand(); -} + connect(ui->projection, SIGNAL(currentIndexChanged(int)), this, SLOT(projectionChanged(int))); + connect(ui->smooth, SIGNAL(stateChanged(int)), this, SLOT(smooth(int))); + connect(ui->hidden, SIGNAL(stateChanged(int)), this, SLOT(hidden(int))); + connect(ui->auto_tog, SIGNAL(stateChanged(int)), this, SLOT(toggle_auto(int))); -void TaskOrthoViews::validate_cbs() -{ - for (int i=0; i < 5; i++) { - for (int j=0; j < 5; j++) { - if ((abs(i-2) + abs(j-2)) < 3) { //if i,j combination corresponds to valid check box, then proceed with: + connect(ui->view_from, SIGNAL(currentIndexChanged(int)), this, SLOT(setPrimary(int))); + connect(ui->axis_right, SIGNAL(currentIndexChanged(int)), this, SLOT(setPrimary(int))); - if (view_count == 0) - { - c_boxes[i][j]->setEnabled(false); - c_boxes[i][j]->setChecked(false); - } - else if (!c_boxes[i][j]->isChecked()) { //only questions boxes 'enableability' if it's not checked - if (view_count == 4) { - c_boxes[i][j]->setEnabled(false); //if there are four checked boxes then all others are disabled - } - else { - if ((abs(i-2) + abs(j-2)) == 1) { //only true for boxes immediately up/down/left/right of centre - c_boxes[i][j]->setEnabled(c_boxes[2][2]->isChecked()); //which are enabled if centre box is checked - } - else { - int di = ((i-2) < 0) - ((i-2) > 0); //which direction is towards centre? - int dj = ((j-2) < 0) - ((j-2) > 0); - - if (c_boxes[i+di][j]->isChecked() + c_boxes[i][j+dj]->isChecked() + (di == 0) + (dj == 0) == 2) - { - if (!((i == 2)*(j == 2))) //don't enable the centre one! -/********temporary if statement here, remove the following if to renable 'diagonal' checkboxes *******/ - //if ((i-2) * (j-2) == 0) - c_boxes[i][j]->setEnabled(true); //if this box's inner neighbour(s) are checked, then this one enabled - } - else - c_boxes[i][j]->setEnabled(false); - } - } - } - } - } - } + connect(ui->axoProj, SIGNAL(activated(int)), this, SLOT(change_axo(int))); + connect(ui->axoUp, SIGNAL(activated(int)), this, SLOT(change_axo(int))); + connect(ui->axoRight, SIGNAL(activated(int)), this, SLOT(change_axo(int))); + connect(ui->vert_flip, SIGNAL(clicked()), this, SLOT(axo_button())); + connect(ui->tri_flip, SIGNAL(clicked()), this, SLOT(axo_button())); + connect(ui->axoScale, SIGNAL(textEdited(const QString &)), this, SLOT(axo_scale(const QString &))); + connect(ui->axoScale, SIGNAL(returnPressed()), this, SLOT(text_return())); + + ui->tabWidget->setTabEnabled(1,false); + + gp_Dir facing = gp_Dir(1, 0, 0); + gp_Dir right = gp_Dir(0, 1, 0); + orthos = new OrthoViews(page, part); + orthos->set_primary(facing, right); + + txt_return = false; +} //end of constructor + + +TaskOrthoViews::~TaskOrthoViews() +{ + delete orthos; + delete ui; } -void TaskOrthoViews::cb_toggled(bool toggle) +void TaskOrthoViews::ShowContextMenu(const QPoint& pos) { QString name = sender()->objectName().right(2); char letter = name.toStdString()[0]; @@ -838,396 +948,361 @@ void TaskOrthoViews::cb_toggled(bool toggle) letter = name.toStdString()[1]; int dy = letter - '0' - 2; - int i = 0; - if (toggle) + if (c_boxes[dx + 2][dy + 2]->isChecked()) { - for (i = 0; i < 4; i++) - { - if (view_status[i][0] == 0) - break; - } - - int direction, rotation; - view_status[i][0] = 1; - view_status[i][2] = dx; - view_status[i][3] = dy; - views[i]->activate(true); - - if (abs(dx * dy) == 1) - { - axo = i; - ui->tabWidget->setTabEnabled(1,true); - ui->axoScale->setText(QString::number(scale)); - set_axo(); - } + QString str_1 = QObject::tr("Make axonometric..."); + QString str_2 = QObject::tr("Edit axonometric settings..."); + QString str_3 = QObject::tr("Make orthographic"); + + QPoint globalPos = c_boxes[dx + 2][dy + 2]->mapToGlobal(pos); + QMenu myMenu; + if (orthos->is_Ortho(dx, -dy)) + myMenu.addAction(str_1); else { - view_data(dx, dy, direction, rotation); - views[i]->setDir(direction); - views[i]->setOrientation(rotation); + myMenu.addAction(str_2); + if (dx * dy == 0) + myMenu.addAction(str_3); } - view_count += 1; - } - else - { - if (((abs(dx) == 1 || abs(dy) == 1)) && (dx*dy) == 0) + + QAction * selectedItem = myMenu.exec(globalPos); + if (selectedItem) { - c_boxes[dx*2+2][dy*2+2]->setChecked(false); - if (abs(dx) == 1) + QString text = selectedItem->text(); + + if (text == str_1) // make axo { - c_boxes[dx+2][1]->setChecked(false); - c_boxes[dx+2][3]->setChecked(false); + orthos->set_Axo(dx, -dy); + axo_r_x = dx; + axo_r_y = dy; + ui->tabWidget->setTabEnabled(1, true); + ui->tabWidget->setCurrentIndex(1); + setup_axo_tab(); } - else + else if (text == str_2) // edit axo { - c_boxes[1][dy+2]->setChecked(false); - c_boxes[3][dy+2]->setChecked(false); + axo_r_x = dx; + axo_r_y = dy; + ui->tabWidget->setTabEnabled(1, true); + ui->tabWidget->setCurrentIndex(1); + setup_axo_tab(); + } + else if (text == str_3) // make ortho + { + orthos->set_Ortho(dx, -dy); + if (dx == axo_r_x && dy == axo_r_y) + { + axo_r_x = 0; + axo_r_y = 0; + ui->tabWidget->setTabEnabled(1, false); + } } } + } +} - for (i = 0; i < 4; i++) - { - if (view_status[i][2] == dx && view_status[i][3] == dy) - break; - } - - if (i == axo) - { - axo = 0; - ui->tabWidget->setTabEnabled(1,false); - } - views[i]->activate(false); - view_status[i][0] = 0; - view_status[i][2] = 0; - view_status[i][3] = 0; - view_count -= 1; +void TaskOrthoViews::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); } - validate_cbs(); - compute(); } -void TaskOrthoViews::view_data(int x, int y, int & direction, int & rotation) +void TaskOrthoViews::cb_toggled(bool toggle) { - int arr_index; - rotate_coords(x,y,(4-rotate)%4); - x = x * proj; - y = y * proj; + QString name = sender()->objectName().right(2); + char letter = name.toStdString()[0]; + int dx = letter - '0' - 2; + + letter = name.toStdString()[1]; + int dy = letter - '0' - 2; - if (primary < 4) + if (toggle) { - if (y == 0) - { - rotation = rotate; - direction = (primary + x + 4) % 4; - } - else + orthos->add_view(dx, -dy); + if (dx * dy != 0) // adding an axo view { - arr_index = (y + 2 - (y > 0)) % 3; //maps (-2,-1,1,2) to (0,1,2,0) - direction = map1[primary][arr_index][0]; - rotation = (map1[primary][arr_index][1] + rotate) % 4; + axo_r_x = dx; + axo_r_y = dy; + ui->tabWidget->setTabEnabled(1, true); + ui->tabWidget->setCurrentIndex(1); + setup_axo_tab(); } } - else + else // removing a view { - int offset = (y != 0); - arr_index = (x == 0)*(y + 2 - (y > 0)) % 3 + (y == 0)*(x + 2 - (x > 0)) % 3; - direction = map2[2*(primary == 5) + offset][arr_index][0]; - rotation = (map2[2*(primary == 5) + offset][arr_index][1] + rotate) % 4; + if (!orthos->is_Ortho(dx, -dy)) // is it an axo one? + { + if (dx == axo_r_x && dy == axo_r_y) // is it the one currently being edited? + { + axo_r_x = 0; + axo_r_y = 0; + ui->tabWidget->setTabEnabled(1, false); + } + } + orthos->del_view(dx, -dy); } + + set_configs(); } void TaskOrthoViews::projectionChanged(int index) { - proj = 2*(0.5-index); //gives -1 for 1st angle and 1 for 3rd - updateSecondaries(); - compute(); + int proj = 3 - 2 * index; // index = 0 = third angle + orthos->set_projection(proj); + + set_configs(); } -void TaskOrthoViews::setRotate(int r) +void TaskOrthoViews::setPrimary(int dir) { - rotate = r; - views[0]->setOrientation(rotate); - updateSecondaries(); - compute(); -} + int p_sel = ui->view_from->currentIndex(); // index for entry selected for 'view from' + int r_sel = ui->axis_right->currentIndex(); // index for entry selected for 'rightwards axis' + int p_vec[3] = {0, 0, 0}; // will be the vector for 'view from' + int r_vec[3] = {0, 0, 0}; // will be vector for 'rightwards axis' + int r[2] = {0, 1}; -void TaskOrthoViews::updateSecondaries() -{ - int direction, rotation; - int dx, dy; - int n; + int pos = 1 - 2 * int(p_sel / 3); // 1 if p_sel = 0, 1, 2 or -1 if p_sel = 3, 4, 5 + p_sel = p_sel % 3; // p_sel = 0, 1, 2 + p_vec[p_sel] = pos; - for (int i = 1; i < 4; i++) - if ((view_status[i][0] == 1) && (i != axo)) - { - dx = view_status[i][2]; - dy = view_status[i][3]; - view_data(dx, dy, direction, rotation); - views[i]->setDir(direction); - views[i]->setOrientation(rotation); - } -} + for (int i = p_sel; i < 2; i++) // make r[2] to be, {0, 1}, {0, 2}, or {1, 2} depending upon p_sel + r[i] += 1; + pos = 1 - 2 * int(r_sel / 2); // 1 if r_sel = 0, 1 or -1 if r_sel = 3, 4 + r_sel = r_sel % 2; // r_sel = 0, 1 + r_vec[r[r_sel]] = pos; -void TaskOrthoViews::setPrimary(int dir) -{ - if (dir == 0) - { - for (int i = 0; i < 4; i++) - { - views[i]->activate(false); - view_status[i][0] = 0; - } - view_count = 0; - c_boxes[2][2]->setChecked(false); - } - else + gp_Dir facing = gp_Dir(p_vec[0], p_vec[1], p_vec[2]); + gp_Dir right = gp_Dir(r_vec[0], r_vec[1], r_vec[2]); + + orthos->set_primary(facing, right); + + // update rightwards combobox in case of 'view from' change + if (sender() == ui->view_from) { - c_boxes[2][2]->setChecked(true); - view_count += (view_count == 0); - primary = dir-1; - view_status[0][0] = 1; - views[0]->setDir(primary); - views[0]->setOrientation(rotate); - views[0]->activate(true); - updateSecondaries(); - compute(); + disconnect(ui->axis_right, SIGNAL(currentIndexChanged(int)), this, SLOT(setPrimary(int))); + + QStringList items; + items << QString::fromUtf8("X +ve") << QString::fromUtf8("Y +ve") << QString::fromUtf8("Z +ve"); + items << QString::fromUtf8("X -ve") << QString::fromUtf8("Y -ve") << QString::fromUtf8("Z -ve"); + items.removeAt(p_sel + 3); + items.removeAt(p_sel); + + ui->axis_right->clear(); + ui->axis_right->addItems(items); + ui->axis_right->setCurrentIndex(r_sel - pos + 1); + + connect(ui->axis_right, SIGNAL(currentIndexChanged(int)), this, SLOT(setPrimary(int))); } - validate_cbs(); + + set_configs(); } void TaskOrthoViews::hidden(int i) { - views[0]->hidden(i); - views[1]->hidden(i); - views[2]->hidden(i); - views[3]->hidden(i); - Command::updateActive(); - Command::commitCommand(); + orthos->set_hidden(i == 2); } void TaskOrthoViews::smooth(int i) { - views[0]->smooth(i); - views[1]->smooth(i); - views[2]->smooth(i); - views[3]->smooth(i); - Command::updateActive(); - Command::commitCommand(); + orthos->set_smooth(i == 2); } -void TaskOrthoViews::axo_flip() +void TaskOrthoViews::toggle_auto(int i) { - axo_flipped = !axo_flipped; - set_axo(); + if (i == 2) //auto scale switched on + { + orthos->auto_dims(true); + ui->label_4->setEnabled(false); + ui->label_5->setEnabled(false); + ui->label_6->setEnabled(false); + + for (int j = 0; j < 5; j++) + inputs[j]->setEnabled(false); //disable user input boxes + } + else + { + orthos->auto_dims(false); + ui->label_4->setEnabled(true); + ui->label_5->setEnabled(true); + ui->label_6->setEnabled(true); + + for (int j = 0; j < 5; j++) + inputs[j]->setEnabled(true); //enable user input boxes + } } -void TaskOrthoViews::axoTopChanged(int i) +void TaskOrthoViews::data_entered(const QString & text) { - QStringList items; - items << QString::fromUtf8("Front") << QString::fromUtf8("Right") << QString::fromUtf8("Back") << QString::fromUtf8("Left") << QString::fromUtf8("Top") << QString::fromUtf8("Bottom"); + bool ok; + QString name = sender()->objectName().right(1); + char letter = name.toStdString()[0]; + int index = letter - '0'; - if (i == 0 || i == 2) - { - items.removeAt(0); - items.removeAt(1); - } - else if (i == 1 || i == 3) + float value = text.toFloat(&ok); + + if (ok) { - items.removeAt(1); - items.removeAt(2); + data[index] = value; + orthos->set_configs(data); } else { - items.removeAt(4); - items.removeAt(4); + inputs[index]->setText(QString::number(data[index])); + return; } - ui->axoLeft->clear(); - ui->axoLeft->addItems(items); - set_axo(); } -void TaskOrthoViews::axoChanged(int i) +void TaskOrthoViews::clean_up() { - if (i == 2) - ui->flip->setEnabled(true); - else - ui->flip->setEnabled(false); - - set_axo(); + orthos->del_all(); } -void TaskOrthoViews::axoScale() +void TaskOrthoViews::setup_axo_tab() { - bool ok; - QString temp = ui->axoScale->text(); + int axo; + gp_Dir up, right; + bool away, tri; + float axo_scale; + int up_n, right_n; + + orthos->get_Axo(axo_r_x, -axo_r_y, axo, up, right, away, tri, axo_scale); + + // convert gp_Dirs into selections of comboboxes + if (up.X() != 0) + up_n = (up.X() == -1) ? 3 : 0; + else if (up.Y() != 0) + up_n = (up.Y() == -1) ? 4 : 1; + else + up_n = (up.Z() == -1) ? 5 : 2; - float value = temp.toFloat(&ok); - if (ok) - { - views[axo]->setScale(value); - compute(); - } + if (right.X() != 0) + right_n = (right.X() == -1) ? 3 : 0; + else if (right.Y() != 0) + right_n = (right.Y() == -1) ? 4 : 1; else - ui->axoScale->setText(temp); + right_n = (right.Z() == -1) ? 5 : 2; + + if (right_n > (up_n % 3 + 3)) + right_n -= 2; + else if (right_n > up_n) + right_n -= 1; + + QStringList items; + items << QString::fromUtf8("X +ve") << QString::fromUtf8("Y +ve") << QString::fromUtf8("Z +ve"); + items << QString::fromUtf8("X -ve") << QString::fromUtf8("Y -ve") << QString::fromUtf8("Z -ve"); + items.removeAt(up_n % 3 + 3); + items.removeAt(up_n % 3); + + ui->axoUp->setCurrentIndex(up_n); + ui->axoRight->clear(); + ui->axoRight->addItems(items); + ui->axoRight->setCurrentIndex(right_n); + + ui->vert_flip->setChecked(away); + ui->tri_flip->setChecked(tri); + ui->axoProj->setCurrentIndex(axo); + ui->axoScale->setText(QString::number(axo_scale)); } -void TaskOrthoViews::set_axo() +void TaskOrthoViews::change_axo(int p) { - float v[3]; - float angle; - int proj, primary, left; + int u_sel = ui->axoUp->currentIndex(); // index for entry selected for 'view from' + int r_sel = ui->axoRight->currentIndex(); // index for entry selected for 'rightwards axis' - proj = ui->axoProj->currentIndex(); - primary = ui->axoTop->currentIndex(); - left = ui->axoLeft->currentIndex(); + int u_vec[3] = {0, 0, 0}; // will be the vector for 'view from' + int r_vec[3] = {0, 0, 0}; // will be vector for 'rightwards axis' + int r[2] = {0, 1}; - v[0] = axonometric[proj][primary][left][0]; - v[1] = axonometric[proj][primary][left][1]; - v[2] = axonometric[proj][primary][left][2]; - angle = axonometric[proj][primary][left][3]; + int pos = 1 - 2 * int(u_sel / 3); // 1 if p_sel = 0,1,2 or -1 if p_sel = 3,4,5 + u_sel = u_sel % 3; // p_sel = 0,1,2 + u_vec[u_sel] = pos; - if (axo_flipped && proj == 2) - { - int max_i = 2; - int min_i = 2; - float abs_v[3] = {abs(v[0]), abs(v[1]), abs(v[2])}; - - if (abs_v[0] < abs_v[1] && abs_v[0] < abs_v[2]) - min_i = 0; - else if (abs_v[1] < abs_v[2]) - min_i = 1; - - if (abs_v[0] > abs_v[1] && abs_v[0] > abs_v[2]) - max_i = 0; - else if (abs_v[1] > abs_v[2]) - max_i = 1; - - v[min_i] = ((v[min_i] > 0) - (v[min_i] < 0)) * abs_v[max_i]; - v[max_i] = ((v[max_i] > 0) - (v[max_i] < 0)) * abs_v[min_i]; - - if (((left == 0 || left == 1) && (primary == 1 || primary == 2)) || - ((left == 2 || left == 3) && (primary == 0 || primary == 3)) || - ((primary == 5) && (left == 0 || left == 2)) || - ((primary == 4) && (left == 1 || left == 3))) - { - angle = - angle; - } - else - { - angle = (angle > 0) ? 98.8 : -81.2; - } - } - views[axo]->setDir(v[0],v[1],v[2], angle, primary); - compute(); -} + for (int i = u_sel; i < 2; i++) + r[i] += 1; + pos = 1 - 2 * int(r_sel / 2); + r_sel = r_sel % 2; + r_vec[r[r_sel]] = pos; -void TaskOrthoViews::toggle_auto(int i) -{ - if (i == 2) //auto scale switched on - { - autoscale = true; - ui->label_4->setEnabled(false); - ui->label_5->setEnabled(false); - ui->label_6->setEnabled(false); - for (int j = 0; j < 5; j++) - inputs[j]->setEnabled(false); //disable user input boxes - compute(); - } + gp_Dir up = gp_Dir(u_vec[0], u_vec[1], u_vec[2]); + gp_Dir right = gp_Dir(r_vec[0], r_vec[1], r_vec[2]); + + orthos->set_Axo(axo_r_x, -axo_r_y, up, right, ui->vert_flip->isChecked(), ui->axoProj->currentIndex(), ui->tri_flip->isChecked()); + + if (ui->axoProj->currentIndex() == 2) + ui->tri_flip->setEnabled(true); else - { - autoscale = false; - ui->label_4->setEnabled(true); - ui->label_5->setEnabled(true); - ui->label_6->setEnabled(true); - for (int j = 0; j < 5; j++) - inputs[j]->setEnabled(true); //enable user input boxes - } + ui->tri_flip->setEnabled(false); + + + QStringList items; + items << QString::fromUtf8("X +ve") << QString::fromUtf8("Y +ve") << QString::fromUtf8("Z +ve"); + items << QString::fromUtf8("X -ve") << QString::fromUtf8("Y -ve") << QString::fromUtf8("Z -ve"); + items.removeAt(u_sel % 3 + 3); + items.removeAt(u_sel % 3); + + ui->axoRight->clear(); + ui->axoRight->addItems(items); + ui->axoRight->setCurrentIndex(r_sel - pos + 1); } -void TaskOrthoViews::data_entered() +void TaskOrthoViews::axo_button() { - //Command::doCommand(Command::Doc,"#1"); - bool ok; + change_axo(); +} - QString name = sender()->objectName().right(1); - char letter = name.toStdString()[0]; - int index = letter - '0'; +void TaskOrthoViews::axo_scale(const QString & text) +{ + bool ok; + float value = text.toFloat(&ok); - float value = inputs[index]->text().toFloat(&ok); if (ok) - *data[index] = value; - else - { - inputs[index]->setText(QString::number(*data[index])); - return; - } - compute(); + orthos->set_Axo_scale(axo_r_x, -axo_r_y, value); } -bool TaskOrthoViews::user_input() +void TaskOrthoViews::set_configs() { - //if user presses return, this is intercepted by FreeCAD which interprets it as activating the 'OK' button - //if return was pressed in a text box though, we don't want it to do 'OK', so check to see if a text box has been modified. - bool modified = false; + orthos->get_configs(data); for (int i = 0; i < 5; i++) - { - modified = inputs[i]->isModified(); //has input box been modified? - if (modified) - { - inputs[i]->setModified(false); //reset modified flag - break; //stop checking - } - } - if (ui->axoScale->isModified()) - { - ui->axoScale->setModified(false); - modified = true; - } - return modified; + inputs[i]->setText(QString::number(data[i])); } -void TaskOrthoViews::clean_up(bool keep) +bool TaskOrthoViews::user_input() { - if (keep) //user ok-ed the drawing - { - if (!views[0]->active) - views[0]->deleteme(); - if (!views[1]->active) - views[1]->deleteme(); - if (!views[2]->active) - views[2]->deleteme(); - if (!views[3]->active) - views[3]->deleteme(); - } - else //user cancelled the drawing + if (txt_return) { - views[0]->deleteme(); - views[1]->deleteme(); - views[2]->deleteme(); - views[3]->deleteme(); + txt_return = false; // return was pressed while text box had focus + ui->label_7->setFocus(); // move focus out of text box + return true; // return that we were editing } + else + return false; // return that we weren't editing ---> treat as clicking OK... we can close the GUI } +void TaskOrthoViews::text_return() +{ + txt_return = true; +} @@ -1265,15 +1340,12 @@ void TaskDlgOrthoViews::clicked(int) bool TaskDlgOrthoViews::accept() { bool check = widget->user_input(); - if (!check) - widget->clean_up(true); - return !check; } bool TaskDlgOrthoViews::reject() { - widget->clean_up(false); + widget->clean_up(); return true; } diff --git a/src/Mod/Drawing/Gui/TaskOrthoViews.h b/src/Mod/Drawing/Gui/TaskOrthoViews.h index 9c88bfa0ee11..5cb9823991d7 100644 --- a/src/Mod/Drawing/Gui/TaskOrthoViews.h +++ b/src/Mod/Drawing/Gui/TaskOrthoViews.h @@ -28,53 +28,127 @@ #include "ui_TaskOrthoViews.h" #include +#include +#include + +#include + + + class Ui_TaskOrthoViews; +using namespace std; namespace DrawingGui { -class orthoView +class orthoview { public: - orthoView(std::string, const char *, const char *, Base::BoundBox3d); - ~orthoView(); - - void activate(bool); - void setDir(int); - void setDir(float,float,float,float,int); - void setPos(float = 0, float = 0); - void setScale(float); - void setOrientation(int); - void deleteme(); - void hidden(int); - void smooth(int); - -public: - bool active; - float width; - float height; + orthoview(App::Document * parent, App::DocumentObject * part, App::DocumentObject * page, Base::BoundBox3d * partbox); + ~orthoview(); + + void set_data(int r_x, int r_y); + void set_projection(gp_Ax2 cs); + void setPos(float = 0, float = 0); + void setScale(float newscale); + float getScale(); + void deleteme(); + void hidden(bool); + void smooth(bool); private: - void calcCentre(); - void updateView(); + void calcCentre(); + +public: // these aren't used by orthoView, but just informational, hence public + bool ortho; // orthonometric? or axonometric + bool auto_scale; // scale for axonometric has not been manually changed? + int rel_x, rel_y; // relative position of this view + bool away, tri; // binary parameters for axonometric view + int axo; // 0 / 1 / 2 = iso / di / tri metric + gp_Dir up, right; // directions prior to rotations (ie, what was used to orientate the projection) private: - std::string myname; - Base::BoundBox3d mybox; - int dir; - float angle; - float n[3]; - int orientation; - float x, y; - float pageX, pageY; - float scale; - bool axo; - float vert[3]; + App::Document * parent_doc; + Drawing::FeatureViewPart * this_view; + + string myname; + float x, y; // 2D projection coords of bbox centre relative to origin + float cx, cy, cz; // coords of bbox centre in 3D space + float pageX, pageY; // required coords of centre of bbox projection on page + float scale; // scale of projection + gp_Dir X_dir, Y_dir, Z_dir; // directions of projection, X_dir makes x on page, Y_dir is y on page, Z_dir is out of page }; +class OrthoViews +{ +public: + OrthoViews(const char * pagename, const char * partname); + ~OrthoViews(); + + void set_primary(gp_Dir facing, gp_Dir right); + void add_view(int rel_x, int rel_y); + void del_view(int rel_x, int rel_y); + void del_all(); + void set_projection(int proj); + void set_hidden(bool state); + void set_smooth(bool state); + void set_Axo(int rel_x, int rel_y, gp_Dir up, gp_Dir right, bool away = false, int axo = 0, bool tri = false); + void set_Axo(int rel_x, int rel_y); + void set_Axo_scale(int rel_x, int rel_y, float axo_scale); + void set_Ortho(int rel_x, int rel_y); + int is_Ortho(int rel_x, int rel_y); + bool get_Axo(int rel_x, int rel_y, int & axo, gp_Dir & up, gp_Dir & right, bool & away, bool & tri, float & axo_scale); + void auto_dims(bool setting); + void set_configs(float configs[5]); + void get_configs(float configs[5]); + +private: + void set_orientation(int index); + void load_page(); // get page / titleblock dims from template + void choose_page(); // determine correct portion of page to use to avoid interference with title block + void set_all_orientations(); // update orientations of all views following change in primary view + void calc_layout_size(); // what's the real world size of chosen layout, excluding spaces + void calc_offsets(); + void set_views(); + void calc_scale(); + void process_views(); + int index(int rel_x, int rel_y); + +private: + vector views; + Base::BoundBox3d bbox; + App::Document * parent_doc; + App::DocumentObject * part; + App::DocumentObject * page; + + string page_name, part_name; + + int large[4]; // arrays containing page size info [margin_x, margin_y, size_x, size_y] = [x1, y1, x2-x1, y2-y1] + int small_h[4], small_v[4]; // page size avoiding title block, using maximum horizontal / vertical space + int * page_dims; // points to one of above arrays for which set of page dimensions to use + int block[4]; // title block info [corner x, corner y, width, height], eg [-1, 1, w, h] is in top left corner + bool title; + int * horiz, * vert; // points to min or max r_x / r_y depending upon which corner title block is in + + int rotate_coeff; // 1st (= -1) or 3rd (= 1) angle + int min_r_x, max_r_x; // extreme relative positions of views + int min_r_y, max_r_y; // " " " + float width, height, depth; // of non-scaled primary view + float layout_width, layout_height; // of non-scaled layout without spaces + float gap_x, gap_y, min_space; // required spacing between views + float offset_x, offset_y; // coords of centre of upper left view + float scale; + int num_gaps_x, num_gaps_y; // how many gaps between views/edges? = num of views in given direction + 1 + gp_Ax2 primary; // coord system of primary view + + bool hidden, smooth; + bool autodims; +}; + + class TaskOrthoViews : public QWidget//: public Gui::TaskView::TaskBox @@ -85,68 +159,41 @@ class TaskOrthoViews : public QWidget//: public Gui::TaskView::TaskBox TaskOrthoViews(QWidget *parent = 0); ~TaskOrthoViews(); bool user_input(); - void clean_up(bool); + void clean_up(); protected Q_SLOTS: - void setPrimary(int); - void setRotate(int); - void cb_toggled(bool); - void projectionChanged(int); - void hidden(int); - void smooth(int); - void toggle_auto(int); - void data_entered(); - void axoChanged(int); - void axoTopChanged(int); - void axo_flip(); - void axoScale(); + void ShowContextMenu(const QPoint & pos); + void setPrimary(int dir); + void cb_toggled(bool toggle); + void projectionChanged(int index); + void hidden(int i); + void smooth(int i); + void toggle_auto(int i); + void data_entered(const QString & text); + void change_axo(int p = 3); + void axo_button(); + void axo_scale(const QString & text); + void text_return(); protected: - void changeEvent(QEvent *); + void changeEvent(QEvent * e); private: - void pagesize(std::string&); - void autodims(); - void compute(); - void validate_cbs(); - void view_data(int, int, int &, int &); - void updateSecondaries(); - void set_axo(); + void setup_axo_tab(); + void set_configs(); private: - class Private; + //class Private; Ui_TaskOrthoViews * ui; - orthoView * views[4]; - QCheckBox * c_boxes[5][5]; //matrix of pointers to gui checkboxes - QLineEdit * inputs[5]; //pointers to manual position/scale boxes - float * data[5]; //pointers to scale, x_pos, y_pos, horiz, vert - - int map1[4][3][2]; //contains view directions and rotations for vertical secondary positions, for primaries 1,2,3,4 - int map2[4][3][2]; //contains view directions and rotations for H and V secondary positions, primaries 5,6 - float axonometric[3][6][4][4]; //contains view direction vectors and rotations for axonometric views - - int view_status[4][4]; //matrix containing status of four orthoView objects (in use, axo, rel x, rel y) - int view_count; //number of active views - - int primary; //view direction of primary view - float x_pos, y_pos; //x and y coords for primary view - int rotate; //rotate primary view clockwise by rotate*90 - int proj; //first (=-1) or third (=1) angle projection - float scale; //scale of drawing - bool autoscale; //whether or not to run autodims - - float horiz, vert; //centre-centre distances - - bool axo_flipped; - int axo; - - float pagewidth, pageheight; //these are actually the available width and height, calculated in constructor. - float pageh1, pageh2; //h1 - total usable page height, h2 - total height allowing for info box. - int margin; - int min_space; //minimum space between views, and page edge -}; + OrthoViews * orthos; + QCheckBox * c_boxes[5][5]; // matrix of pointers to gui checkboxes + QLineEdit * inputs[5]; // pointers to manual position/scale boxes + float data[5]; // scale, x_pos, y_pos, horiz, vert + int axo_r_x, axo_r_y; // relative position of axo view currently being edited + bool txt_return; // flag to show if return was pressed while editing a text box; +}; ////////////////////////////////////////////////////////////// @@ -162,20 +209,15 @@ class TaskDlgOrthoViews : public Gui::TaskView::TaskDialog TaskDlgOrthoViews(); ~TaskDlgOrthoViews(); - public: void open(); bool accept(); bool reject(); void clicked(int); -// QDialogButtonBox::StandardButtons getStandardButtons() const -// { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } - private: TaskOrthoViews * widget; Gui::TaskView::TaskBox* taskbox; - }; } //namespace DrawingGui diff --git a/src/Mod/Drawing/Gui/TaskOrthoViews.ui b/src/Mod/Drawing/Gui/TaskOrthoViews.ui index 33d9e4b92305..1c0d07f53c32 100644 --- a/src/Mod/Drawing/Gui/TaskOrthoViews.ui +++ b/src/Mod/Drawing/Gui/TaskOrthoViews.ui @@ -6,8 +6,8 @@ 0 0 - 259 - 496 + 250 + 486 @@ -31,7 +31,7 @@ - false + true @@ -39,6 +39,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -50,7 +56,7 @@ - false + true @@ -58,6 +64,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -69,7 +81,7 @@ - false + true @@ -77,6 +89,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -88,7 +106,7 @@ - false + true @@ -96,6 +114,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -107,7 +131,7 @@ - false + true @@ -115,6 +139,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -132,7 +162,7 @@ - false + true @@ -140,6 +170,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -151,7 +187,7 @@ - false + true @@ -159,6 +195,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -170,7 +212,7 @@ - false + true @@ -178,6 +220,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -189,7 +237,7 @@ - false + true @@ -197,6 +245,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -208,7 +262,7 @@ - false + true @@ -216,6 +270,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -227,7 +287,7 @@ - false + true @@ -235,6 +295,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -264,7 +330,7 @@ - false + true @@ -281,7 +347,7 @@ - false + true @@ -289,6 +355,12 @@ 0 + + Qt::CustomContextMenu + + + Right click for axonometric settings + Qt::RightToLeft @@ -393,7 +465,7 @@ false - Primary x / y + Top left x / y 2 @@ -441,7 +513,7 @@ false - Secondary dx / dy + Spacing dx / dy 2 @@ -507,8 +579,59 @@ Axonometric - + + + + + Axis out and right + + + + + + + Vertical tilt + + + + + + + true + + + + X +ve + + + + + Y +ve + + + + + Z +ve + + + + + X -ve + + + + + Y -ve + + + + + Z -ve + + + + @@ -531,17 +654,7 @@ - - - - false - - - Switch direction - - - - + Scale @@ -558,95 +671,77 @@ - Top face + Axis aligned up - - - - Left face - - - - - + + true - Front + Y +ve - Right + Z +ve - Back + Y -ve - Left - - - - - Top - - - - - Bottom + Z -ve - - + + true - - - Right - - - - - Left - - - - - Top - - - - - Bottom - - - - + + + Flip + + true + + false + - + Trimetric + + + + false + + + Flip + + + true + + + @@ -693,12 +788,12 @@ - Primary View + View from: - + QComboBox::AdjustToContentsOnFirstShow @@ -707,37 +802,32 @@ - - - - - - Front + X +ve - Right + Y +ve - Back + Z +ve - Left + X -ve - Top + Y -ve - Bottom + Z -ve @@ -745,33 +835,33 @@ - - Rotate + Axis aligned right: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + - 0 + Y +ve - 90 + Z +ve - 180 + Y -ve - 270 + Z -ve diff --git a/src/Mod/Drawing/Templates/A3_Landscape.svg b/src/Mod/Drawing/Templates/A3_Landscape.svg index d30384799b13..9d2535ac6832 100644 --- a/src/Mod/Drawing/Templates/A3_Landscape.svg +++ b/src/Mod/Drawing/Templates/A3_Landscape.svg @@ -18,6 +18,8 @@ inkscape:version="0.48.1 r9760" sodipodi:docname="A3_Landscape.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"> + + diff --git a/src/Mod/Drawing/Templates/A4_Landscape.svg b/src/Mod/Drawing/Templates/A4_Landscape.svg index 018c614dc3ab..dcc5ae73e395 100644 --- a/src/Mod/Drawing/Templates/A4_Landscape.svg +++ b/src/Mod/Drawing/Templates/A4_Landscape.svg @@ -17,6 +17,8 @@ inkscape:version="0.47 r22583" sodipodi:docname="A4_Landscape.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"> + + diff --git a/src/Mod/Plot/InitGui.py b/src/Mod/Plot/InitGui.py index 2afc60afae4e..c72e1dfa66a9 100644 --- a/src/Mod/Plot/InitGui.py +++ b/src/Mod/Plot/InitGui.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,26 +21,42 @@ #* * #*************************************************************************** -class PlotWorkbench ( Workbench ): - """ @brief Workbench of Plot module. Here toolbars & icons are append. """ - from plotUtils import Paths - import PlotGui - Icon = 'Icon.svg' - MenuText = "Plot" - ToolTip = "The Plot module is used to edit/save output plots performed by other tools" +class PlotWorkbench(Workbench): + """Workbench of Plot module.""" + from plotUtils import Paths + import PlotGui + + Icon = 'Icon.svg' + MenuText = "Plot" + ToolTip = ("The Plot module is used to edit/save output plots performed " + "by other tools") + + def Initialize(self): + from PySide import QtCore, QtGui + cmdlst = ["Plot_SaveFig", + "Plot_Axes", + "Plot_Series", + "Plot_Grid", + "Plot_Legend", + "Plot_Labels", + "Plot_Positions"] + self.appendToolbar(str(QtCore.QT_TRANSLATE_NOOP( + "Plot", + "Plot edition tools")), cmdlst) + self.appendMenu(str(QtCore.QT_TRANSLATE_NOOP( + "Plot", + "Plot")), cmdlst) + try: + import matplotlib + except ImportError: + from PySide import QtCore, QtGui + msg = QtGui.QApplication.translate( + "plot_console", + "matplotlib not found, Plot module will be disabled", + None, + QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintMessage(msg + '\n') - def Initialize(self): - from PyQt4 import QtCore, QtGui - cmdlst = ["Plot_SaveFig", "Plot_Axes", "Plot_Series", "Plot_Grid", "Plot_Legend", "Plot_Labels", "Plot_Positions"] - self.appendToolbar(str(QtCore.QT_TRANSLATE_NOOP("Plot", "Plot edition tools")),cmdlst) - self.appendMenu(str(QtCore.QT_TRANSLATE_NOOP("Plot", "Plot")),cmdlst) - try: - import matplotlib - except ImportError: - from PyQt4 import QtCore, QtGui - msg = QtGui.QApplication.translate("plot_console", "matplotlib not found, Plot module will be disabled", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage(msg + '\n') Gui.addWorkbench(PlotWorkbench()) diff --git a/src/Mod/Plot/Plot.py b/src/Mod/Plot/Plot.py index c943363a6072..95b3bcd2cc52 100644 --- a/src/Mod/Plot/Plot.py +++ b/src/Mod/Plot/Plot.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,301 +21,409 @@ #* * #*************************************************************************** -# FreeCAD import FreeCAD -# PyQt4 -from PyQt4 import QtCore, QtGui +import PySide +from PySide import QtCore, QtGui -# Matplot lib try: - import matplotlib - import matplotlib.pyplot as plt - from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas - from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar - from matplotlib.figure import Figure + import matplotlib + matplotlib.use('Qt4Agg') + matplotlib.rcParams['backend.qt4']='PySide' + import matplotlib.pyplot as plt + from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas + from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar + from matplotlib.figure import Figure except ImportError: - msg = QtGui.QApplication.translate("plot_console", "matplotlib not found, so Plot module can not be loaded", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintMessage(msg + '\n') - raise ImportError("matplotlib not installed") + msg = QtGui.QApplication.translate( + "plot_console", + "matplotlib not found, so Plot module can not be loaded", + None, + QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintMessage(msg + '\n') + raise ImportError("matplotlib not installed") + def getMainWindow(): - """ getMainWindow(): Gets FreeCAD main window. """ - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - return None + """ Return the FreeCAD main window. """ + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + return None + def getMdiArea(): - """ getMdiArea(): Gets FreeCAD MdiArea. """ - mw = getMainWindow() - if not mw: - return None - return mw.findChild(QtGui.QMdiArea) + """ Return FreeCAD MdiArea. """ + mw = getMainWindow() + if not mw: + return None + childs = mw.children() + for c in childs: + if isinstance(c, PySide.QtGui.QMdiArea): + return c + return None + def getPlot(): - """ getPlot(): Gets selected Plot document if exist. """ - # Get active tab - mdi = getMdiArea() - if not mdi: - return None - sub = mdi.activeSubWindow() - if not sub: - return None - # Explore childrens looking for Plot class - for i in sub.children(): - if i.metaObject().className() == "Plot": - return i - return None + """ Return the selected Plot document if exist. """ + # Get active tab + mdi = getMdiArea() + if not mdi: + return None + sub = mdi.activeSubWindow() + if not sub: + return None + # Explore childrens looking for Plot class + for i in sub.children(): + if i.metaObject().className() == "Plot": + return i + return None + def figure(winTitle="plot"): - """ figure(winTitle="plot"): Create a new plot subwindow.\n winTitle = Tab title. """ - mdi = getMdiArea() - if not mdi: - return None - win = Plot(winTitle) - sub=mdi.addSubWindow(win) - sub.show() - return win - -def plot(x,y,name=None): - """ plot(x,y,name=None): Plots a new serie (as line plot)\n x = X values\n y = Y values\n name = Serie name (for legend). """ - # Get active plot, or create another one if don't exist - plt = getPlot() - if not plt: - plt = figure() - # Call to plot - return plt.plot(x,y,name) + """Create a new plot subwindow/tab. + + Keyword arguments: + winTitle -- Plot tab title. + """ + mdi = getMdiArea() + if not mdi: + return None + win = Plot(winTitle) + sub = mdi.addSubWindow(win) + sub.show() + return win + + +def plot(x, y, name=None): + """Plots a new serie (as line plot) + + Keyword arguments: + x -- X values + y -- Y values + name -- Data serie name (for legend). + """ + # Get active plot, or create another one if don't exist + plt = getPlot() + if not plt: + plt = figure() + # Call to plot + return plt.plot(x, y, name) + def series(): - """ lines(): Get all lines from selected plot. """ - plt = getPlot() - if not plt: - return [] - return plt.series + """Return all the lines from a selected plot.""" + plt = getPlot() + if not plt: + return [] + return plt.series + def removeSerie(index): - """ removeSerie(index): Removes a serie from plot.\n index = Index of serie to remove. """ - # Get active series - plt = getPlot() - if not plt: - return - plots = plt.series - if not plots: - return - # Remove line from plot - axes = plots[index].axes - axes.lines.pop(plots[index].lid) - # Remove serie from list - del plt.series[index] - # Update GUI - plt.update() + """Remove a data serie from the active plot. + + Keyword arguments: + index -- Index of the serie to remove. + """ + # Get active series + plt = getPlot() + if not plt: + return + plots = plt.series + if not plots: + return + # Remove line from plot + axes = plots[index].axes + axes.lines.pop(plots[index].lid) + # Remove serie from list + del plt.series[index] + # Update GUI + plt.update() + def legend(status=True, pos=None, fontsize=None): - """ legend(status=True): Show/Hide legend.\n status = True if legend must be shown, False otherwise.\n pos = Legend position.\n fontsize = Font size """ - plt = getPlot() - if not plt: - return - plt.legend = status - if fontsize: - plt.legSiz = fontsize - # Hide all legends - for axes in plt.axesList: - axes.legend_ = None - # Legend must be activated on last axes - axes = plt.axesList[-1] - if status: - # Setup legend handles and names - lines = series() - handles = [] - names = [] - for l in lines: - if l.name != None: - handles.append(l.line) - names.append(l.name) - # Show the legend (at selected position or at best) - if pos: - l = axes.legend(handles, names, bbox_to_anchor=pos) - plt.legPos = pos - else: - l = axes.legend(handles, names, loc='best') - # Update canvas in order to compute legend data - plt.canvas.draw() - # Get resultant position - fax = axes.get_frame().get_extents() - fl = l.get_frame() - plt.legPos = ((fl._x+fl._width-fax.x0) / fax.width, (fl._y+fl._height-fax.y0) / fax.height) - # Set fontsize - for t in l.get_texts(): - t.set_fontsize(plt.legSiz) - plt.update() + """Show/Hide the legend from the active plot. + + Keyword arguments: + status -- True if legend must be shown, False otherwise. + pos -- Legend position. + fontsize -- Font size + """ + plt = getPlot() + if not plt: + return + plt.legend = status + if fontsize: + plt.legSiz = fontsize + # Hide all legends + for axes in plt.axesList: + axes.legend_ = None + # Legend must be activated on last axes + axes = plt.axesList[-1] + if status: + # Setup legend handles and names + lines = series() + handles = [] + names = [] + for l in lines: + if l.name is not None: + handles.append(l.line) + names.append(l.name) + # Show the legend (at selected position or at best) + if pos: + l = axes.legend(handles, names, bbox_to_anchor=pos) + plt.legPos = pos + else: + l = axes.legend(handles, names, loc='best') + # Update canvas in order to compute legend data + plt.canvas.draw() + # Get resultant position + fax = axes.get_frame().get_extents() + fl = l.get_frame() + plt.legPos = ( + (fl._x + fl._width - fax.x0) / fax.width, + (fl._y + fl._height - fax.y0) / fax.height) + # Set fontsize + for t in l.get_texts(): + t.set_fontsize(plt.legSiz) + plt.update() + def grid(status=True): - """ grid(status=True): Show/Hide grid.\n status = True if grid must be shown, False otherwise. """ - plt = getPlot() - if not plt: - return - plt.grid = status - axes = plt.axes - axes.grid(status) - plt.update() + """Show/Hide the grid from the active plot. + + Keyword arguments: + status -- True if grid must be shown, False otherwise. + """ + plt = getPlot() + if not plt: + return + plt.grid = status + axes = plt.axes + axes.grid(status) + plt.update() + def title(string): - """ title(string): Setup plot title.\n string = Title to set. """ - plt = getPlot() - if not plt: - return - axes = plt.axes - axes.set_title(string) - plt.update() + """Setup the plot title. + + Keyword arguments: + string -- Plot title. + """ + plt = getPlot() + if not plt: + return + axes = plt.axes + axes.set_title(string) + plt.update() + def xlabel(string): - """ xlabel(string): Setup x label.\n string = Title to set. """ - plt = getPlot() - if not plt: - return - axes = plt.axes - axes.set_xlabel(string) - plt.update() + """Setup the x label. + + Keyword arguments: + string -- Title to set. + """ + plt = getPlot() + if not plt: + return + axes = plt.axes + axes.set_xlabel(string) + plt.update() + def ylabel(string): - """ ylabel(string): Setup y label.\n string = Title to set. """ - plt = getPlot() - if not plt: - return - axes = plt.axes - axes.set_ylabel(string) - plt.update() + """Setup the y label. + + Keyword arguments: + string -- Title to set. + """ + plt = getPlot() + if not plt: + return + axes = plt.axes + axes.set_ylabel(string) + plt.update() + def axesList(): - """ axesList(): Gets plot axes list. """ - plt = getPlot() - if not plt: - return [] - return plt.axesList + """Return the plot axes sets list. """ + plt = getPlot() + if not plt: + return [] + return plt.axesList + def axes(): - """ axes(): Gets active plot axes. """ - plt = getPlot() - if not plt: - return None - return plt.axes + """Return the active plot axes.""" + plt = getPlot() + if not plt: + return None + return plt.axes + def addNewAxes(rect=None, frameon=True, patchcolor='none'): - """ addNewAxes(pos=None, frameon=True): Add new axes to plot, setting it as active one.\n rect = Axes area, None to copy last axes data.\n frameon = True to show frame, False otherwise.\n patchcolor = Patch color, 'none' for transparent plot. """ - plt = getPlot() - if not plt: - return None - fig = plt.fig - if rect == None: - rect = plt.axes.get_position() - ax = fig.add_axes(rect, frameon=frameon) - ax.xaxis.set_ticks_position('bottom') - ax.spines['top'].set_color('none') - ax.yaxis.set_ticks_position('left') - ax.spines['right'].set_color('none') - ax.patch.set_facecolor(patchcolor) - plt.axesList.append(ax) - plt.setActiveAxes(-1) - plt.update() - return ax + """Add new axes to plot, setting it as the active one. + + Keyword arguments: + rect -- Axes area, None to copy from the last axes data. + frameon -- True to show frame, False otherwise. + patchcolor -- Patch color, 'none' for transparent plot. + """ + plt = getPlot() + if not plt: + return None + fig = plt.fig + if rect is None: + rect = plt.axes.get_position() + ax = fig.add_axes(rect, frameon=frameon) + ax.xaxis.set_ticks_position('bottom') + ax.spines['top'].set_color('none') + ax.yaxis.set_ticks_position('left') + ax.spines['right'].set_color('none') + ax.patch.set_facecolor(patchcolor) + plt.axesList.append(ax) + plt.setActiveAxes(-1) + plt.update() + return ax + def save(path, figsize=None, dpi=None): - """ save(path): Save plot.\n path = Destination file path.\n figsize = w,h figure size tuple in inches.\n dpi = Dots per inch.""" - plt = getPlot() - if not plt: - return - # Backup figure options - fig = plt.fig - sizeBack = fig.get_size_inches() - dpiBack = fig.get_dpi() - # Save figure with new options - if figsize: - fig.set_size_inches(figsize[0], figsize[1]) - if dpi: - fig.set_dpi(dpi) - plt.canvas.print_figure(path) - # Restore figure options - fig.set_size_inches(sizeBack[0], sizeBack[1]) - fig.set_dpi(dpiBack) - plt.update() + """Save plot. + + Keyword arguments: + path -- Destination file path. + figsize -- w,h figure size tuple in inches. + dpi -- Dots per inch. + """ + plt = getPlot() + if not plt: + return + # Backup figure options + fig = plt.fig + sizeBack = fig.get_size_inches() + dpiBack = fig.get_dpi() + # Save figure with new options + if figsize: + fig.set_size_inches(figsize[0], figsize[1]) + if dpi: + fig.set_dpi(dpi) + plt.canvas.print_figure(path) + # Restore figure options + fig.set_size_inches(sizeBack[0], sizeBack[1]) + fig.set_dpi(dpiBack) + plt.update() + class Line(): - def __init__(self, axes, x, y, name): - """ __init__(axes, x, y, name): Construct new plot serie.\n axes = Active axes\n x = X values\n y = Y values\n name = Serie name (for legend). """ - self.axes = axes - self.x = x - self.y = y - self.name = name - self.lid = len(axes.lines) - self.line, = axes.plot(x,y) - - def setp(self, prop, value): - """ setp(prop, value): Change line property value.\n prop = Property name.\n value = New property value. """ - plt.setp(self.line, prop, value) - - def getp(self, prop): - """ getp(prop): Get property value.\n prop = Property name.""" - return plt.getp(self.line, prop) + def __init__(self, axes, x, y, name): + """Construct a new plot serie. + + Keyword arguments: + axes -- Active axes + x -- X values + y -- Y values + name -- Data serie name (for legend). + """ + self.axes = axes + self.x = x + self.y = y + self.name = name + self.lid = len(axes.lines) + self.line, = axes.plot(x, y) + + def setp(self, prop, value): + """Change a line property value. + + Keyword arguments: + prop -- Property name. + value -- New property value. + """ + plt.setp(self.line, prop, value) + + def getp(self, prop): + """Get line property value. + + Keyword arguments: + prop -- Property name. + """ + return plt.getp(self.line, prop) + class Plot(QtGui.QWidget): - def __init__(self, winTitle="plot", parent = None, flags = QtCore.Qt.WindowFlags(0)): - """ __init__(winTitle="plot", parent = None, flags = Qt.WindowFlags(0)): Construct a new plot widget.\n winTitle = Tab title.\n parent = Widget parent.\n flags = QWidget flags""" - QtGui.QWidget.__init__(self, parent, flags) - self.setWindowTitle(winTitle) - # Create matplotlib canvas - self.fig = Figure() - self.canvas = FigureCanvas(self.fig) - self.canvas.setParent(self) - # Get axes - self.axes = self.fig.add_subplot(111) - self.axesList = [self.axes] - self.axes.xaxis.set_ticks_position('bottom') - self.axes.spines['top'].set_color('none') - self.axes.yaxis.set_ticks_position('left') - self.axes.spines['right'].set_color('none') - # Setup layout - vbox = QtGui.QVBoxLayout() - vbox.addWidget(self.canvas) - self.setLayout(vbox) - # Active series - self.series = [] - # Indicators - self.skip = False - self.legend = False - self.legPos = (1.0,1.0) - self.legSiz = 14 - self.grid = False - - def plot(self, x, y, name=None): - """ plot(self, x, y, name=None): Plot a new line and return it.\n x = X values\n y = Y values\n name = Serie name (for legend). """ - l = Line(self.axes, x, y, name) - self.series.append(l) - # Update window - self.update() - return l - - def update(self): - """ update(): Updates plot. """ - if not self.skip: - self.skip = True - if self.legend: - legend(self.legend, self.legPos, self.legSiz) - self.canvas.draw() - self.skip = False - - def isGrid(self): - """ isGrid(): Return True if Grid is active, False otherwise. """ - return bool(self.grid) - - def isLegend(self): - """ isLegend(): Return True if Legend is active, False otherwise. """ - return bool(self.legend) - - def setActiveAxes(self, index): - """ setActiveAxes(index): Change current active axes.\n index = Index of the new active axes. """ - self.axes = self.axesList[index] - self.fig.sca(self.axes) + def __init__(self, + winTitle="plot", + parent=None, + flags=QtCore.Qt.WindowFlags(0)): + """Construct a new plot widget. + + Keyword arguments: + winTitle -- Tab title. + parent -- Widget parent. + flags -- QWidget flags + """ + QtGui.QWidget.__init__(self, parent, flags) + self.setWindowTitle(winTitle) + # Create matplotlib canvas + self.fig = Figure() + self.canvas = FigureCanvas(self.fig) + self.canvas.setParent(self) + # Get axes + self.axes = self.fig.add_subplot(111) + self.axesList = [self.axes] + self.axes.xaxis.set_ticks_position('bottom') + self.axes.spines['top'].set_color('none') + self.axes.yaxis.set_ticks_position('left') + self.axes.spines['right'].set_color('none') + # Setup layout + vbox = QtGui.QVBoxLayout() + vbox.addWidget(self.canvas) + self.setLayout(vbox) + # Active series + self.series = [] + # Indicators + self.skip = False + self.legend = False + self.legPos = (1.0, 1.0) + self.legSiz = 14 + self.grid = False + + def plot(self, x, y, name=None): + """Plot a new line and return it. + + Keyword arguments: + x -- X values + y -- Y values + name -- Serie name (for legend). """ + l = Line(self.axes, x, y, name) + self.series.append(l) + # Update window + self.update() + return l + + def update(self): + """Update the plot, redrawing the canvas.""" + if not self.skip: + self.skip = True + if self.legend: + legend(self.legend, self.legPos, self.legSiz) + self.canvas.draw() + self.skip = False + + def isGrid(self): + """Return True if Grid is active, False otherwise.""" + return bool(self.grid) + + def isLegend(self): + """Return True if Legend is active, False otherwise.""" + return bool(self.legend) + + def setActiveAxes(self, index): + """Change the current active axes. + Keyword arguments: + index -- Index of the new active axes set. + """ + self.axes = self.axesList[index] + self.fig.sca(self.axes) diff --git a/src/Mod/Plot/PlotGui.py b/src/Mod/Plot/PlotGui.py index 0f7a3c639edc..189545522063 100644 --- a/src/Mod/Plot/PlotGui.py +++ b/src/Mod/Plot/PlotGui.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,126 +21,163 @@ #* * #*************************************************************************** -from PyQt4 import QtCore, QtGui -import FreeCAD, FreeCADGui, os +import PySide +from PySide import QtCore, QtGui +import FreeCAD +import FreeCADGui +import os -# Load resources import Plot_rc + + FreeCADGui.addLanguagePath(":/Plot/translations") FreeCADGui.addIconPath(":/Plot/icons") -""" -# Setup tranlations -from plotUtils import Paths -path = Paths.translationsPath() -FreeCADGui.addLanguagePath(path) -import os -import FreeCAD -translator = QtCore.QTranslator() -dirList=os.listdir(path) -for fname in dirList: - valid = translator.load(os.path.join(path, fname)) - if valid: - QtGui.QApplication.installTranslator(translator) -""" - -class Save: - def Activated(self): - import plotSave - plotSave.load() - - def GetResources(self): - # from plotUtils import Paths - # IconPath = Paths.iconsPath() + "/Save.svg" - MenuText = QtCore.QT_TRANSLATE_NOOP("Plot_SaveFig", "Save plot") - ToolTip = QtCore.QT_TRANSLATE_NOOP("Plot_SaveFig", "Save plot as image file") - return {'Pixmap' : 'Save', 'MenuText': MenuText, 'ToolTip': ToolTip} - -class Axes: - def Activated(self): - import plotAxes - plotAxes.load() - - def GetResources(self): - # from plotUtils import Paths - # IconPath = Paths.iconsPath() + "/Axes.svg" - MenuText = QtCore.QT_TRANSLATE_NOOP("Plot_Axes", "Configure axes") - ToolTip = QtCore.QT_TRANSLATE_NOOP("Plot_Axes", "Configure axes parameters") - return {'Pixmap' : 'Axes', 'MenuText': MenuText, 'ToolTip': ToolTip} - -class Series: - def Activated(self): - import plotSeries - plotSeries.load() - - def GetResources(self): - # from plotUtils import Paths - # IconPath = Paths.iconsPath() + "/Series.svg" - MenuText = QtCore.QT_TRANSLATE_NOOP("Plot_Series", "Configure series") - ToolTip = QtCore.QT_TRANSLATE_NOOP("Plot_Series", "Configure series drawing style and label") - return {'Pixmap' : 'Series', 'MenuText': MenuText, 'ToolTip': ToolTip} - -class Grid: - def Activated(self): - import Plot - plt = Plot.getPlot() - if not plt: - msg = QtGui.QApplication.translate("plot_console", "Grid must be activated on top of a plot document", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintError(msg+"\n") - return - flag = plt.isGrid() - Plot.grid(not flag) - - def GetResources(self): - # from plotUtils import Paths - # IconPath = Paths.iconsPath() + "/Grid.svg" - MenuText = QtCore.QT_TRANSLATE_NOOP("Plot_Grid", "Show/Hide grid") - ToolTip = QtCore.QT_TRANSLATE_NOOP("Plot_Grid", "Show/Hide grid on selected plot") - return {'Pixmap' : 'Grid', 'MenuText': MenuText, 'ToolTip': ToolTip} - -class Legend: - def Activated(self): - import Plot - plt = Plot.getPlot() - if not plt: - msg = QtGui.QApplication.translate("plot_console", "Legend must be activated on top of a plot document", - None,QtGui.QApplication.UnicodeUTF8) - FreeCAD.Console.PrintError(msg+"\n") - return - flag = plt.isLegend() - Plot.legend(not flag) - - def GetResources(self): - # from plotUtils import Paths - # IconPath = Paths.iconsPath() + "/Legend.svg" - MenuText = QtCore.QT_TRANSLATE_NOOP("Plot_Legend", "Show/Hide legend") - ToolTip = QtCore.QT_TRANSLATE_NOOP("Plot_Legend", "Show/Hide legend on selected plot") - return {'Pixmap' : 'Legend', 'MenuText': MenuText, 'ToolTip': ToolTip} - -class Labels: - def Activated(self): - import plotLabels - plotLabels.load() - - def GetResources(self): - # from plotUtils import Paths - # IconPath = Paths.iconsPath() + "/Labels.svg" - MenuText = QtCore.QT_TRANSLATE_NOOP("Plot_Labels", "Set labels") - ToolTip = QtCore.QT_TRANSLATE_NOOP("Plot_Labels", "Set title and axes labels") - return {'Pixmap' : 'Labels', 'MenuText': MenuText, 'ToolTip': ToolTip} - -class Positions: - def Activated(self): - import plotPositions - plotPositions.load() - - def GetResources(self): - # from plotUtils import Paths - # IconPath = Paths.iconsPath() + "/Positions.svg" - MenuText = QtCore.QT_TRANSLATE_NOOP("Plot_Positions", "Set positions and sizes") - ToolTip = QtCore.QT_TRANSLATE_NOOP("Plot_Positions", "Set labels and legend positions and sizes") - return {'Pixmap' : 'Positions', 'MenuText': MenuText, 'ToolTip': ToolTip} + +class Save: + def Activated(self): + import plotSave + plotSave.load() + + def GetResources(self): + # from plotUtils import Paths + # IconPath = Paths.iconsPath() + "/Save.svg" + MenuText = QtCore.QT_TRANSLATE_NOOP( + "Plot_SaveFig", + "Save plot") + ToolTip = QtCore.QT_TRANSLATE_NOOP( + "Plot_SaveFig", + "Save the plot as an image file") + return {'Pixmap': 'Save', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + + +class Axes: + def Activated(self): + import plotAxes + plotAxes.load() + + def GetResources(self): + MenuText = QtCore.QT_TRANSLATE_NOOP( + "Plot_Axes", + "Configure axes") + ToolTip = QtCore.QT_TRANSLATE_NOOP( + "Plot_Axes", + "Configure the axes parameters") + return {'Pixmap': 'Axes', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + + +class Series: + def Activated(self): + import plotSeries + plotSeries.load() + + def GetResources(self): + # from plotUtils import Paths + # IconPath = Paths.iconsPath() + "/Series.svg" + MenuText = QtCore.QT_TRANSLATE_NOOP( + "Plot_Series", + "Configure series") + ToolTip = QtCore.QT_TRANSLATE_NOOP( + "Plot_Series", + "Configure series drawing style and label") + return {'Pixmap': 'Series', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + + +class Grid: + def Activated(self): + import Plot + plt = Plot.getPlot() + if not plt: + msg = QtGui.QApplication.translate( + "plot_console", + "The grid must be activated on top of a plot document", + None, + QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintError(msg + "\n") + return + flag = plt.isGrid() + Plot.grid(not flag) + + def GetResources(self): + # from plotUtils import Paths + # IconPath = Paths.iconsPath() + "/Grid.svg" + MenuText = QtCore.QT_TRANSLATE_NOOP( + "Plot_Grid", + "Show/Hide grid") + ToolTip = QtCore.QT_TRANSLATE_NOOP( + "Plot_Grid", + "Show/Hide grid on selected plot") + return {'Pixmap': 'Grid', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + + +class Legend: + def Activated(self): + import Plot + plt = Plot.getPlot() + if not plt: + msg = QtGui.QApplication.translate( + "plot_console", + "The legend must be activated on top of a plot document", + None, + QtGui.QApplication.UnicodeUTF8) + FreeCAD.Console.PrintError(msg + "\n") + return + flag = plt.isLegend() + Plot.legend(not flag) + + def GetResources(self): + MenuText = QtCore.QT_TRANSLATE_NOOP( + "Plot_Legend", + "Show/Hide legend") + ToolTip = QtCore.QT_TRANSLATE_NOOP( + "Plot_Legend", + "Show/Hide legend on selected plot") + return {'Pixmap': 'Legend', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + + +class Labels: + def Activated(self): + import plotLabels + plotLabels.load() + + def GetResources(self): + MenuText = QtCore.QT_TRANSLATE_NOOP( + "Plot_Labels", + "Set labels") + ToolTip = QtCore.QT_TRANSLATE_NOOP( + "Plot_Labels", + "Set title and axes labels") + return {'Pixmap': 'Labels', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + + +class Positions: + def Activated(self): + import plotPositions + plotPositions.load() + + def GetResources(self): + MenuText = QtCore.QT_TRANSLATE_NOOP( + "Plot_Positions", + "Set positions and sizes") + ToolTip = QtCore.QT_TRANSLATE_NOOP( + "Plot_Positions", + "Set labels and legend positions and sizes") + return {'Pixmap': 'Positions', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + FreeCADGui.addCommand('Plot_SaveFig', Save()) FreeCADGui.addCommand('Plot_Axes', Axes()) @@ -149,4 +186,3 @@ def GetResources(self): FreeCADGui.addCommand('Plot_Legend', Legend()) FreeCADGui.addCommand('Plot_Labels', Labels()) FreeCADGui.addCommand('Plot_Positions', Positions()) - diff --git a/src/Mod/Plot/Plot_rc.py b/src/Mod/Plot/Plot_rc.py index 7840d561bdeb..f2c29b177f23 100644 --- a/src/Mod/Plot/Plot_rc.py +++ b/src/Mod/Plot/Plot_rc.py @@ -7,7 +7,7 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore +from PySide import QtCore qt_resource_data = "\ \x00\x00\x00\x10\ diff --git a/src/Mod/Plot/plotAxes/TaskPanel.py b/src/Mod/Plot/plotAxes/TaskPanel.py index 35d165853278..5a89c60ca279 100644 --- a/src/Mod/Plot/plotAxes/TaskPanel.py +++ b/src/Mod/Plot/plotAxes/TaskPanel.py @@ -1,463 +1,673 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* 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 Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* 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 Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * #* License along with this program; if not, write to the Free Software * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * +#* USA * +#* * #*************************************************************************** -# FreeCAD modules import FreeCAD as App import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module + +from PySide import QtGui, QtCore + import Plot from plotUtils import Paths + class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/plotAxes/TaskPanel.ui" - self.skip = False - - def accept(self): - return True - - def reject(self): - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.axId = form.findChild(QtGui.QSpinBox, "axesIndex") - form.new = form.findChild(QtGui.QPushButton, "newAxesButton") - form.remove = form.findChild(QtGui.QPushButton, "delAxesButton") - form.all = form.findChild(QtGui.QCheckBox, "allAxes") - form.xMin = form.findChild(QtGui.QSlider, "posXMin") - form.xMax = form.findChild(QtGui.QSlider, "posXMax") - form.yMin = form.findChild(QtGui.QSlider, "posYMin") - form.yMax = form.findChild(QtGui.QSlider, "posYMax") - form.xAlign = form.findChild(QtGui.QComboBox, "xAlign") - form.yAlign = form.findChild(QtGui.QComboBox, "yAlign") - form.xOffset = form.findChild(QtGui.QSpinBox, "xOffset") - form.yOffset = form.findChild(QtGui.QSpinBox, "yOffset") - form.xAuto = form.findChild(QtGui.QCheckBox, "xAuto") - form.yAuto = form.findChild(QtGui.QCheckBox, "yAuto") - form.xSMin = form.findChild(QtGui.QLineEdit, "xMin") - form.xSMax = form.findChild(QtGui.QLineEdit, "xMax") - form.ySMin = form.findChild(QtGui.QLineEdit, "yMin") - form.ySMax = form.findChild(QtGui.QLineEdit, "yMax") - self.form = form - self.retranslateUi() - # Look for active axes if can - axId = 0 - plt = Plot.getPlot() - if plt: - while plt.axes != plt.axesList[axId]: - axId = axId + 1 - form.axId.setValue(axId) - self.updateUI() - QtCore.QObject.connect(form.axId, QtCore.SIGNAL('valueChanged(int)'),self.onAxesId) - QtCore.QObject.connect(form.new, QtCore.SIGNAL("pressed()"),self.onNew) - QtCore.QObject.connect(form.remove, QtCore.SIGNAL("pressed()"),self.onRemove) - QtCore.QObject.connect(form.xMin, QtCore.SIGNAL("valueChanged(int)"),self.onDims) - QtCore.QObject.connect(form.xMax, QtCore.SIGNAL("valueChanged(int)"),self.onDims) - QtCore.QObject.connect(form.yMin, QtCore.SIGNAL("valueChanged(int)"),self.onDims) - QtCore.QObject.connect(form.yMax, QtCore.SIGNAL("valueChanged(int)"),self.onDims) - QtCore.QObject.connect(form.xAlign, QtCore.SIGNAL("currentIndexChanged(int)"),self.onAlign) - QtCore.QObject.connect(form.yAlign, QtCore.SIGNAL("currentIndexChanged(int)"),self.onAlign) - QtCore.QObject.connect(form.xOffset,QtCore.SIGNAL("valueChanged(int)"),self.onOffset) - QtCore.QObject.connect(form.yOffset,QtCore.SIGNAL("valueChanged(int)"),self.onOffset) - QtCore.QObject.connect(form.xAuto, QtCore.SIGNAL("stateChanged(int)"),self.onScales) - QtCore.QObject.connect(form.yAuto, QtCore.SIGNAL("stateChanged(int)"),self.onScales) - QtCore.QObject.connect(form.xSMin, QtCore.SIGNAL("editingFinished()"),self.onScales) - QtCore.QObject.connect(form.xSMax, QtCore.SIGNAL("editingFinished()"),self.onScales) - QtCore.QObject.connect(form.ySMin, QtCore.SIGNAL("editingFinished()"),self.onScales) - QtCore.QObject.connect(form.ySMax, QtCore.SIGNAL("editingFinished()"),self.onScales) - QtCore.QObject.connect(Plot.getMdiArea(),QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"),self.onMdiArea) - return False - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(QtGui.QApplication.translate("plot_axes", "Configure axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "axesLabel").setText(QtGui.QApplication.translate("plot_axes", "Active axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.all.setText(QtGui.QApplication.translate("plot_axes", "Apply to all axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "dimLabel").setText(QtGui.QApplication.translate("plot_axes", "Dimensions", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "xPosLabel").setText(QtGui.QApplication.translate("plot_axes", "X axis position", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "yPosLabel").setText(QtGui.QApplication.translate("plot_axes", "Y axis position", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "scalesLabel").setText(QtGui.QApplication.translate("plot_axes", "Scales", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.xAuto.setText(QtGui.QApplication.translate("plot_axes", "X auto", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.yAuto.setText(QtGui.QApplication.translate("plot_axes", "Y auto", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QCheckBox, "allAxes").setText(QtGui.QApplication.translate("plot_axes", "Apply to all axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "dimLabel").setText(QtGui.QApplication.translate("plot_axes", "Dimensions", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "xPosLabel").setText(QtGui.QApplication.translate("plot_axes", "X axis position", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "yPosLabel").setText(QtGui.QApplication.translate("plot_axes", "Y axis position", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.axId.setToolTip(QtGui.QApplication.translate("plot_axes", "Index of the active axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.new.setToolTip(QtGui.QApplication.translate("plot_axes", "Add new axes to the plot", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.remove.setToolTip(QtGui.QApplication.translate("plot_axes", "Remove selected axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.all.setToolTip(QtGui.QApplication.translate("plot_axes", "Check it to apply transformations to all axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.xMin.setToolTip(QtGui.QApplication.translate("plot_axes", "Left bound of axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.xMax.setToolTip(QtGui.QApplication.translate("plot_axes", "Right bound of axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.yMin.setToolTip(QtGui.QApplication.translate("plot_axes", "Bottom bound of axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.yMax.setToolTip(QtGui.QApplication.translate("plot_axes", "Top bound of axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.xOffset.setToolTip(QtGui.QApplication.translate("plot_axes", "Outward offset of X axis", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.yOffset.setToolTip(QtGui.QApplication.translate("plot_axes", "Outward offset of Y axis", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.xAuto.setToolTip(QtGui.QApplication.translate("plot_axes", "X axis scale autoselection", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.yAuto.setToolTip(QtGui.QApplication.translate("plot_axes", "Y axis scale autoselection", - None,QtGui.QApplication.UnicodeUTF8)) - - def onAxesId(self, value): - """ Executed when axes index is modified. """ - if not self.skip: - self.skip = True - # UI control in some special plot cases - plt = Plot.getPlot() - if not plt: - self.updateUI() - self.skip = False - return - # UI control in most cases - self.form.axId.setMaximum(len(plt.axesList)) - if self.form.axId.value() >= len(plt.axesList): - self.form.axId.setValue(len(plt.axesList)-1) - # Send new control to Plot instance - plt.setActiveAxes(self.form.axId.value()) - self.updateUI() - self.skip = False - - def onNew(self): - """ Executed when new axes must be created. """ - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - Plot.addNewAxes() - self.form.axId.setValue(len(plt.axesList)-1) - plt.update() - - def onRemove(self): - """ Executed when axes must be deleted. """ - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - # Don't remove first axes - if not self.form.axId.value(): - msg = QtGui.QApplication.translate("plot_console", "Axes 0 can not be deleted", - None,QtGui.QApplication.UnicodeUTF8) - App.Console.PrintError(msg+"\n") - return - # Remove axes - ax = plt.axes - ax.set_axis_off() - plt.axesList.pop(self.form.axId.value()) - # Ensure that active axes is correct - index = min(self.form.axId.value(), len(plt.axesList)-1) - self.form.axId.setValue(index) - plt.update() - - def onDims(self, value): - """ Executed when axes dims have been modified. """ - # Get apply environment - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - axesList = [plt.axes] - if self.form.all.isChecked(): - axesList = plt.axesList - # Set new dimensions - xmin = self.form.xMin.value() / 100.0 - xmax = self.form.xMax.value() / 100.0 - ymin = self.form.yMin.value() / 100.0 - ymax = self.form.yMax.value() / 100.0 - for axes in axesList: - axes.set_position([xmin, ymin, xmax-xmin, ymax-ymin]) - plt.update() - - def onAlign(self, value): - """ Executed when axes align have been modified. """ - # Get apply environment - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - axesList = [plt.axes] - if self.form.all.isChecked(): - axesList = plt.axesList - # Set new alignement - for axes in axesList: - if self.form.xAlign.currentIndex() == 0: - axes.xaxis.tick_bottom() - axes.spines['bottom'].set_color((0.0,0.0,0.0)) - axes.spines['top'].set_color('none') - axes.xaxis.set_ticks_position('bottom') - axes.xaxis.set_label_position('bottom') - else: - axes.xaxis.tick_top() - axes.spines['top'].set_color((0.0,0.0,0.0)) - axes.spines['bottom'].set_color('none') - axes.xaxis.set_ticks_position('top') - axes.xaxis.set_label_position('top') - if self.form.yAlign.currentIndex() == 0: - axes.yaxis.tick_left() - axes.spines['left'].set_color((0.0,0.0,0.0)) - axes.spines['right'].set_color('none') - axes.yaxis.set_ticks_position('left') - axes.yaxis.set_label_position('left') - else: - axes.yaxis.tick_right() - axes.spines['right'].set_color((0.0,0.0,0.0)) - axes.spines['left'].set_color('none') - axes.yaxis.set_ticks_position('right') - axes.yaxis.set_label_position('right') - plt.update() - - def onOffset(self, value): - """ Executed when axes offsets have been modified. """ - # Get apply environment - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - axesList = [plt.axes] - if self.form.all.isChecked(): - axesList = plt.axesList - # Set new offset - for axes in axesList: - # For some reason, modify spines offset erase axes labels, so we - # need store it in order to regenerate later - x = axes.get_xlabel() - y = axes.get_ylabel() - for loc, spine in axes.spines.iteritems(): - if loc in ['bottom', 'top']: - spine.set_position(('outward',self.form.xOffset.value())) - if loc in ['left', 'right']: - spine.set_position(('outward',self.form.yOffset.value())) - # Now we can restore axes labels - Plot.xlabel(unicode(x)) - Plot.ylabel(unicode(y)) - plt.update() - - def onScales(self): - """ Executed when axes scales have been modified. """ - # Get apply environment - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - axesList = [plt.axes] - if self.form.all.isChecked(): - axesList = plt.axesList - if not self.skip: - self.skip = True - # X axis - if self.form.xAuto.isChecked(): - for ax in axesList: - ax.set_autoscalex_on(True) - self.form.xSMin.setEnabled(False) - self.form.xSMax.setEnabled(False) - lim = plt.axes.get_xlim() - self.form.xSMin.setText(str(lim[0])) - self.form.xSMax.setText(str(lim[1])) - else: - self.form.xSMin.setEnabled(True) - self.form.xSMax.setEnabled(True) - try: - xMin = float(self.form.xSMin.text()) - except: - xMin = plt.axes.get_xlim()[0] - self.form.xSMin.setText(str(xMin)) - try: - xMax = float(self.form.xSMax.text()) - except: - xMax = plt.axes.get_xlim()[1] - self.form.xSMax.setText(str(xMax)) - for ax in axesList: - ax.set_xlim(( xMin,xMax )) - # Y axis - if self.form.yAuto.isChecked(): - for ax in axesList: - ax.set_autoscaley_on(True) - self.form.ySMin.setEnabled(False) - self.form.ySMax.setEnabled(False) - lim = plt.axes.get_ylim() - self.form.ySMin.setText(str(lim[0])) - self.form.ySMax.setText(str(lim[1])) - else: - self.form.ySMin.setEnabled(True) - self.form.ySMax.setEnabled(True) - try: - yMin = float(self.form.ySMin.text()) - except: - yMin = plt.axes.get_ylim()[0] - self.form.ySMin.setText(str(yMin)) - try: - yMax = float(self.form.ySMax.text()) - except: - yMax = plt.axes.get_ylim()[1] - self.form.ySMax.setText(str(yMax)) - for ax in axesList: - ax.set_ylim(( yMin,yMax )) - plt.update() - self.skip = False - - def onMdiArea(self, subWin): - """ Executed when window is selected on mdi area. - @param subWin Selected window. - """ - plt = Plot.getPlot() - if plt != subWin: - self.updateUI() - - def updateUI(self): - """ Setup UI controls values if possible """ - plt = Plot.getPlot() - self.form.axId.setEnabled(bool(plt)) - self.form.new.setEnabled(bool(plt)) - self.form.remove.setEnabled(bool(plt)) - self.form.all.setEnabled(bool(plt)) - self.form.xMin.setEnabled(bool(plt)) - self.form.xMax.setEnabled(bool(plt)) - self.form.yMin.setEnabled(bool(plt)) - self.form.yMax.setEnabled(bool(plt)) - self.form.xAlign.setEnabled(bool(plt)) - self.form.yAlign.setEnabled(bool(plt)) - self.form.xOffset.setEnabled(bool(plt)) - self.form.yOffset.setEnabled(bool(plt)) - self.form.xAuto.setEnabled(bool(plt)) - self.form.yAuto.setEnabled(bool(plt)) - self.form.xSMin.setEnabled(bool(plt)) - self.form.xSMax.setEnabled(bool(plt)) - self.form.ySMin.setEnabled(bool(plt)) - self.form.ySMax.setEnabled(bool(plt)) - if not plt: - return - # Ensure that active axes is correct - index = min(self.form.axId.value(), len(plt.axesList)-1) - self.form.axId.setValue(index) - # Set dimensions - ax = plt.axes - bb = ax.get_position() - self.form.xMin.setValue(int(100*bb._get_xmin())) - self.form.xMax.setValue(int(100*bb._get_xmax())) - self.form.yMin.setValue(int(100*bb._get_ymin())) - self.form.yMax.setValue(int(100*bb._get_ymax())) - # Set alignment and offset - xPos = ax.xaxis.get_ticks_position() - yPos = ax.yaxis.get_ticks_position() - xOffset = ax.spines['bottom'].get_position()[1] - yOffset = ax.spines['left'].get_position()[1] - if xPos == 'bottom' or xPos == 'default': - self.form.xAlign.setCurrentIndex(0) - else: - self.form.xAlign.setCurrentIndex(1) - self.form.xOffset.setValue(xOffset) - if yPos == 'left' or yPos == 'default': - self.form.yAlign.setCurrentIndex(0) - else: - self.form.yAlign.setCurrentIndex(1) - self.form.yOffset.setValue(yOffset) - # Set scales - if ax.get_autoscalex_on(): - self.form.xAuto.setChecked(True) - self.form.xSMin.setEnabled(False) - self.form.xSMax.setEnabled(False) - else: - self.form.xAuto.setChecked(False) - self.form.xSMin.setEnabled(True) - self.form.xSMax.setEnabled(True) - lim = ax.get_xlim() - self.form.xSMin.setText(str(lim[0])) - self.form.xSMax.setText(str(lim[1])) - if ax.get_autoscaley_on(): - self.form.yAuto.setChecked(True) - self.form.ySMin.setEnabled(False) - self.form.ySMax.setEnabled(False) - else: - self.form.yAuto.setChecked(False) - self.form.ySMin.setEnabled(True) - self.form.ySMax.setEnabled(True) - lim = ax.get_ylim() - self.form.ySMin.setText(str(lim[0])) - self.form.ySMax.setText(str(lim[1])) + def __init__(self): + self.ui = Paths.modulePath() + "/plotAxes/TaskPanel.ui" + self.skip = False + + def accept(self): + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + self.form = form + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + form.new = self.widget(QtGui.QPushButton, "newAxesButton") + form.remove = self.widget(QtGui.QPushButton, "delAxesButton") + form.all = self.widget(QtGui.QCheckBox, "allAxes") + form.xMin = self.widget(QtGui.QSlider, "posXMin") + form.xMax = self.widget(QtGui.QSlider, "posXMax") + form.yMin = self.widget(QtGui.QSlider, "posYMin") + form.yMax = self.widget(QtGui.QSlider, "posYMax") + form.xAlign = self.widget(QtGui.QComboBox, "xAlign") + form.yAlign = self.widget(QtGui.QComboBox, "yAlign") + form.xOffset = self.widget(QtGui.QSpinBox, "xOffset") + form.yOffset = self.widget(QtGui.QSpinBox, "yOffset") + form.xAuto = self.widget(QtGui.QCheckBox, "xAuto") + form.yAuto = self.widget(QtGui.QCheckBox, "yAuto") + form.xSMin = self.widget(QtGui.QLineEdit, "xMin") + form.xSMax = self.widget(QtGui.QLineEdit, "xMax") + form.ySMin = self.widget(QtGui.QLineEdit, "yMin") + form.ySMax = self.widget(QtGui.QLineEdit, "yMax") + self.retranslateUi() + # Look for active axes if can + axId = 0 + plt = Plot.getPlot() + if plt: + while plt.axes != plt.axesList[axId]: + axId = axId + 1 + form.axId.setValue(axId) + self.updateUI() + QtCore.QObject.connect(form.axId, + QtCore.SIGNAL('valueChanged(int)'), + self.onAxesId) + QtCore.QObject.connect(form.new, + QtCore.SIGNAL("pressed()"), + self.onNew) + QtCore.QObject.connect(form.remove, + QtCore.SIGNAL("pressed()"), + self.onRemove) + QtCore.QObject.connect(form.xMin, + QtCore.SIGNAL("valueChanged(int)"), + self.onDims) + QtCore.QObject.connect(form.xMax, + QtCore.SIGNAL("valueChanged(int)"), + self.onDims) + QtCore.QObject.connect(form.yMin, + QtCore.SIGNAL("valueChanged(int)"), + self.onDims) + QtCore.QObject.connect(form.yMax, + QtCore.SIGNAL("valueChanged(int)"), + self.onDims) + QtCore.QObject.connect(form.xAlign, + QtCore.SIGNAL("currentIndexChanged(int)"), + self.onAlign) + QtCore.QObject.connect(form.yAlign, + QtCore.SIGNAL("currentIndexChanged(int)"), + self.onAlign) + QtCore.QObject.connect(form.xOffset, + QtCore.SIGNAL("valueChanged(int)"), + self.onOffset) + QtCore.QObject.connect(form.yOffset, + QtCore.SIGNAL("valueChanged(int)"), + self.onOffset) + QtCore.QObject.connect(form.xAuto, + QtCore.SIGNAL("stateChanged(int)"), + self.onScales) + QtCore.QObject.connect(form.yAuto, + QtCore.SIGNAL("stateChanged(int)"), + self.onScales) + QtCore.QObject.connect(form.xSMin, + QtCore.SIGNAL("editingFinished()"), + self.onScales) + QtCore.QObject.connect(form.xSMax, + QtCore.SIGNAL("editingFinished()"), + self.onScales) + QtCore.QObject.connect(form.ySMin, + QtCore.SIGNAL("editingFinished()"), + self.onScales) + QtCore.QObject.connect(form.ySMax, + QtCore.SIGNAL("editingFinished()"), + self.onScales) + QtCore.QObject.connect( + Plot.getMdiArea(), + QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"), + self.onMdiArea) + return False + + def getMainWindow(self): + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def widget(self, class_id, name): + """Return the selected widget. + + Keyword arguments: + class_id -- Class identifier + name -- Name of the widget + """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + return form.findChild(class_id, name) + + def retranslateUi(self): + """Set the user interface locale strings. + """ + form = self.form + form.setWindowTitle(QtGui.QApplication.translate( + "plot_axes", + "Configure axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "axesLabel").setText( + QtGui.QApplication.translate("plot_axes", + "Active axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "allAxes").setText( + QtGui.QApplication.translate("plot_axes", + "Apply to all axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "dimLabel").setText( + QtGui.QApplication.translate("plot_axes", + "Dimensions", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "xPosLabel").setText( + QtGui.QApplication.translate("plot_axes", + "X axis position", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "yPosLabel").setText( + QtGui.QApplication.translate("plot_axes", + "Y axis position", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "scalesLabel").setText( + QtGui.QApplication.translate("plot_axes", + "Scales", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "xAuto").setText( + QtGui.QApplication.translate("plot_axes", + "X auto", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "yAuto").setText( + QtGui.QApplication.translate("plot_axes", + "Y auto", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "allAxes").setText( + QtGui.QApplication.translate("plot_axes", + "Apply to all axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "dimLabel").setText( + QtGui.QApplication.translate("plot_axes", + "Dimensions", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "xPosLabel").setText( + QtGui.QApplication.translate("plot_axes", + "X axis position", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "yPosLabel").setText( + QtGui.QApplication.translate("plot_axes", + "Y axis position", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "axesIndex").setToolTip( + QtGui.QApplication.translate("plot_axes", + "Index of the active axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QPushButton, "newAxesButton").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Add new axes to the plot", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QPushButton, "delAxesButton").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Remove selected axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "allAxes").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Check it to apply transformations to all axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSlider, "posXMin").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Left bound of axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSlider, "posXMax").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Right bound of axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSlider, "posYMin").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Bottom bound of axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSlider, "posYMax").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Top bound of axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "xOffset").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Outward offset of X axis", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "yOffset").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Outward offset of Y axis", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "xAuto").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "X axis scale autoselection", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "yAuto").setToolTip( + QtGui.QApplication.translate( + "plot_axes", + "Y axis scale autoselection", + None, + QtGui.QApplication.UnicodeUTF8)) + + def onAxesId(self, value): + """Executed when axes index is modified.""" + if not self.skip: + self.skip = True + # No active plot case + plt = Plot.getPlot() + if not plt: + self.updateUI() + self.skip = False + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + + form.axId.setMaximum(len(plt.axesList)) + if form.axId.value() >= len(plt.axesList): + form.axId.setValue(len(plt.axesList) - 1) + # Send new control to Plot instance + plt.setActiveAxes(form.axId.value()) + self.updateUI() + self.skip = False + + def onNew(self): + """Executed when new axes must be created.""" + # Ensure that we can work + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + + Plot.addNewAxes() + form.axId.setValue(len(plt.axesList) - 1) + plt.update() + + def onRemove(self): + """Executed when axes must be deleted.""" + # Ensure taht we can work + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + + # Don't remove first axes + if not form.axId.value(): + msg = QtGui.QApplication.translate( + "plot_console", + "Axes 0 can not be deleted", + None, + QtGui.QApplication.UnicodeUTF8) + App.Console.PrintError(msg + "\n") + return + # Remove axes + ax = plt.axes + ax.set_axis_off() + plt.axesList.pop(form.axId.value()) + # Ensure that active axes is correct + index = min(form.axId.value(), len(plt.axesList) - 1) + form.axId.setValue(index) + plt.update() + + def onDims(self, value): + """Executed when axes dims have been modified.""" + # Ensure that we can work + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.all = self.widget(QtGui.QCheckBox, "allAxes") + form.xMin = self.widget(QtGui.QSlider, "posXMin") + form.xMax = self.widget(QtGui.QSlider, "posXMax") + form.yMin = self.widget(QtGui.QSlider, "posYMin") + form.yMax = self.widget(QtGui.QSlider, "posYMax") + + axesList = [plt.axes] + if form.all.isChecked(): + axesList = plt.axesList + # Set new dimensions + xmin = form.xMin.value() / 100.0 + xmax = form.xMax.value() / 100.0 + ymin = form.yMin.value() / 100.0 + ymax = form.yMax.value() / 100.0 + for axes in axesList: + axes.set_position([xmin, ymin, xmax - xmin, ymax - ymin]) + plt.update() + + def onAlign(self, value): + """Executed when axes align have been modified.""" + # Ensure that we can work + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.all = self.widget(QtGui.QCheckBox, "allAxes") + form.xAlign = self.widget(QtGui.QComboBox, "xAlign") + form.yAlign = self.widget(QtGui.QComboBox, "yAlign") + + axesList = [plt.axes] + if form.all.isChecked(): + axesList = plt.axesList + # Set new alignement + for axes in axesList: + if form.xAlign.currentIndex() == 0: + axes.xaxis.tick_bottom() + axes.spines['bottom'].set_color((0.0, 0.0, 0.0)) + axes.spines['top'].set_color('none') + axes.xaxis.set_ticks_position('bottom') + axes.xaxis.set_label_position('bottom') + else: + axes.xaxis.tick_top() + axes.spines['top'].set_color((0.0, 0.0, 0.0)) + axes.spines['bottom'].set_color('none') + axes.xaxis.set_ticks_position('top') + axes.xaxis.set_label_position('top') + if form.yAlign.currentIndex() == 0: + axes.yaxis.tick_left() + axes.spines['left'].set_color((0.0, 0.0, 0.0)) + axes.spines['right'].set_color('none') + axes.yaxis.set_ticks_position('left') + axes.yaxis.set_label_position('left') + else: + axes.yaxis.tick_right() + axes.spines['right'].set_color((0.0, 0.0, 0.0)) + axes.spines['left'].set_color('none') + axes.yaxis.set_ticks_position('right') + axes.yaxis.set_label_position('right') + plt.update() + + def onOffset(self, value): + """Executed when axes offsets have been modified.""" + # Ensure that we can work + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.all = self.widget(QtGui.QCheckBox, "allAxes") + form.xOffset = self.widget(QtGui.QSpinBox, "xOffset") + form.yOffset = self.widget(QtGui.QSpinBox, "yOffset") + + axesList = [plt.axes] + if form.all.isChecked(): + axesList = plt.axesList + # Set new offset + for axes in axesList: + # For some reason, modify spines offset erase axes labels, so we + # need store it in order to regenerate later + x = axes.get_xlabel() + y = axes.get_ylabel() + for loc, spine in axes.spines.iteritems(): + if loc in ['bottom', 'top']: + spine.set_position(('outward', form.xOffset.value())) + if loc in ['left', 'right']: + spine.set_position(('outward', form.yOffset.value())) + # Now we can restore axes labels + Plot.xlabel(unicode(x)) + Plot.ylabel(unicode(y)) + plt.update() + + def onScales(self): + """Executed when axes scales have been modified.""" + # Ensure that we can work + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.all = self.widget(QtGui.QCheckBox, "allAxes") + form.xAuto = self.widget(QtGui.QCheckBox, "xAuto") + form.yAuto = self.widget(QtGui.QCheckBox, "yAuto") + form.xSMin = self.widget(QtGui.QLineEdit, "xMin") + form.xSMax = self.widget(QtGui.QLineEdit, "xMax") + form.ySMin = self.widget(QtGui.QLineEdit, "yMin") + form.ySMax = self.widget(QtGui.QLineEdit, "yMax") + + axesList = [plt.axes] + if form.all.isChecked(): + axesList = plt.axesList + if not self.skip: + self.skip = True + # X axis + if form.xAuto.isChecked(): + for ax in axesList: + ax.set_autoscalex_on(True) + form.xSMin.setEnabled(False) + form.xSMax.setEnabled(False) + lim = plt.axes.get_xlim() + form.xSMin.setText(str(lim[0])) + form.xSMax.setText(str(lim[1])) + else: + form.xSMin.setEnabled(True) + form.xSMax.setEnabled(True) + try: + xMin = float(form.xSMin.text()) + except: + xMin = plt.axes.get_xlim()[0] + form.xSMin.setText(str(xMin)) + try: + xMax = float(form.xSMax.text()) + except: + xMax = plt.axes.get_xlim()[1] + form.xSMax.setText(str(xMax)) + for ax in axesList: + ax.set_xlim((xMin, xMax)) + # Y axis + if form.yAuto.isChecked(): + for ax in axesList: + ax.set_autoscaley_on(True) + form.ySMin.setEnabled(False) + form.ySMax.setEnabled(False) + lim = plt.axes.get_ylim() + form.ySMin.setText(str(lim[0])) + form.ySMax.setText(str(lim[1])) + else: + form.ySMin.setEnabled(True) + form.ySMax.setEnabled(True) + try: + yMin = float(form.ySMin.text()) + except: + yMin = plt.axes.get_ylim()[0] + form.ySMin.setText(str(yMin)) + try: + yMax = float(form.ySMax.text()) + except: + yMax = plt.axes.get_ylim()[1] + form.ySMax.setText(str(yMax)) + for ax in axesList: + ax.set_ylim((yMin, yMax)) + plt.update() + self.skip = False + + def onMdiArea(self, subWin): + """Executed when window is selected on mdi area. + + Keyword arguments: + subWin -- Selected window. + """ + plt = Plot.getPlot() + if plt != subWin: + self.updateUI() + + def updateUI(self): + """Setup UI controls values if possible""" + plt = Plot.getPlot() + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + form.new = self.widget(QtGui.QPushButton, "newAxesButton") + form.remove = self.widget(QtGui.QPushButton, "delAxesButton") + form.all = self.widget(QtGui.QCheckBox, "allAxes") + form.xMin = self.widget(QtGui.QSlider, "posXMin") + form.xMax = self.widget(QtGui.QSlider, "posXMax") + form.yMin = self.widget(QtGui.QSlider, "posYMin") + form.yMax = self.widget(QtGui.QSlider, "posYMax") + form.xAlign = self.widget(QtGui.QComboBox, "xAlign") + form.yAlign = self.widget(QtGui.QComboBox, "yAlign") + form.xOffset = self.widget(QtGui.QSpinBox, "xOffset") + form.yOffset = self.widget(QtGui.QSpinBox, "yOffset") + form.xAuto = self.widget(QtGui.QCheckBox, "xAuto") + form.yAuto = self.widget(QtGui.QCheckBox, "yAuto") + form.xSMin = self.widget(QtGui.QLineEdit, "xMin") + form.xSMax = self.widget(QtGui.QLineEdit, "xMax") + form.ySMin = self.widget(QtGui.QLineEdit, "yMin") + form.ySMax = self.widget(QtGui.QLineEdit, "yMax") + # Enable/disable them + form.axId.setEnabled(bool(plt)) + form.new.setEnabled(bool(plt)) + form.remove.setEnabled(bool(plt)) + form.all.setEnabled(bool(plt)) + form.xMin.setEnabled(bool(plt)) + form.xMax.setEnabled(bool(plt)) + form.yMin.setEnabled(bool(plt)) + form.yMax.setEnabled(bool(plt)) + form.xAlign.setEnabled(bool(plt)) + form.yAlign.setEnabled(bool(plt)) + form.xOffset.setEnabled(bool(plt)) + form.yOffset.setEnabled(bool(plt)) + form.xAuto.setEnabled(bool(plt)) + form.yAuto.setEnabled(bool(plt)) + form.xSMin.setEnabled(bool(plt)) + form.xSMax.setEnabled(bool(plt)) + form.ySMin.setEnabled(bool(plt)) + form.ySMax.setEnabled(bool(plt)) + if not plt: + form.axId.setValue(0) + return + # Ensure that active axes is correct + index = min(form.axId.value(), len(plt.axesList) - 1) + form.axId.setValue(index) + # Set dimensions + ax = plt.axes + bb = ax.get_position() + form.xMin.setValue(int(100 * bb._get_xmin())) + form.xMax.setValue(int(100 * bb._get_xmax())) + form.yMin.setValue(int(100 * bb._get_ymin())) + form.yMax.setValue(int(100 * bb._get_ymax())) + # Set alignment and offset + xPos = ax.xaxis.get_ticks_position() + yPos = ax.yaxis.get_ticks_position() + xOffset = ax.spines['bottom'].get_position()[1] + yOffset = ax.spines['left'].get_position()[1] + if xPos == 'bottom' or xPos == 'default': + form.xAlign.setCurrentIndex(0) + else: + form.xAlign.setCurrentIndex(1) + form.xOffset.setValue(xOffset) + if yPos == 'left' or yPos == 'default': + form.yAlign.setCurrentIndex(0) + else: + form.yAlign.setCurrentIndex(1) + form.yOffset.setValue(yOffset) + # Set scales + if ax.get_autoscalex_on(): + form.xAuto.setChecked(True) + form.xSMin.setEnabled(False) + form.xSMax.setEnabled(False) + else: + form.xAuto.setChecked(False) + form.xSMin.setEnabled(True) + form.xSMax.setEnabled(True) + lim = ax.get_xlim() + form.xSMin.setText(str(lim[0])) + form.xSMax.setText(str(lim[1])) + if ax.get_autoscaley_on(): + form.yAuto.setChecked(True) + form.ySMin.setEnabled(False) + form.ySMax.setEnabled(False) + else: + form.yAuto.setChecked(False) + form.ySMin.setEnabled(True) + form.ySMax.setEnabled(True) + lim = ax.get_ylim() + form.ySMin.setText(str(lim[0])) + form.ySMax.setText(str(lim[1])) + def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Plot/plotAxes/__init__.py b/src/Mod/Plot/plotAxes/__init__.py index 24058d7a93ee..6a97f58b26af 100644 --- a/src/Mod/Plot/plotAxes/__init__.py +++ b/src/Mod/Plot/plotAxes/__init__.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,16 +21,9 @@ #* * #*************************************************************************** -# FreeCAD modules -import FreeCAD -import FreeCADGui - -# Qt libraries -from PyQt4 import QtGui,QtCore - -# Main object import TaskPanel + def load(): - """ Loads the tool """ - TaskPanel.createTask() + """Load the tool""" + TaskPanel.createTask() diff --git a/src/Mod/Plot/plotLabels/TaskPanel.py b/src/Mod/Plot/plotLabels/TaskPanel.py index f2ea4106dfa4..87dddcb9d720 100644 --- a/src/Mod/Plot/plotLabels/TaskPanel.py +++ b/src/Mod/Plot/plotLabels/TaskPanel.py @@ -1,225 +1,322 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* 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 Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* 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 Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * #* License along with this program; if not, write to the Free Software * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * +#* USA * +#* * #*************************************************************************** -# FreeCAD modules import FreeCAD as App import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module + +from PySide import QtGui, QtCore + import Plot from plotUtils import Paths + class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/plotLabels/TaskPanel.ui" - self.skip = False - - def accept(self): - return True - - def reject(self): - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.axId = form.findChild(QtGui.QSpinBox, "axesIndex") - form.title = form.findChild(QtGui.QLineEdit, "title") - form.titleSize = form.findChild(QtGui.QSpinBox, "titleSize") - form.xLabel = form.findChild(QtGui.QLineEdit, "titleX") - form.xSize = form.findChild(QtGui.QSpinBox, "xSize") - form.yLabel = form.findChild(QtGui.QLineEdit, "titleY") - form.ySize = form.findChild(QtGui.QSpinBox, "ySize") - self.form = form - self.retranslateUi() - # Look for active axes if can - axId = 0 - plt = Plot.getPlot() - if plt: - while plt.axes != plt.axesList[axId]: - axId = axId + 1 - form.axId.setValue(axId) - self.updateUI() - QtCore.QObject.connect(form.axId, QtCore.SIGNAL('valueChanged(int)'),self.onAxesId) - QtCore.QObject.connect(form.title, QtCore.SIGNAL("editingFinished()"),self.onLabels) - QtCore.QObject.connect(form.xLabel, QtCore.SIGNAL("editingFinished()"),self.onLabels) - QtCore.QObject.connect(form.yLabel, QtCore.SIGNAL("editingFinished()"),self.onLabels) - QtCore.QObject.connect(form.titleSize,QtCore.SIGNAL("valueChanged(int)"),self.onFontSizes) - QtCore.QObject.connect(form.xSize, QtCore.SIGNAL("valueChanged(int)"),self.onFontSizes) - QtCore.QObject.connect(form.ySize, QtCore.SIGNAL("valueChanged(int)"),self.onFontSizes) - QtCore.QObject.connect(Plot.getMdiArea(),QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"),self.onMdiArea) - return False - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(QtGui.QApplication.translate("plot_labels", "Set labels", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "axesLabel").setText(QtGui.QApplication.translate("plot_labels", "Active axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "titleLabel").setText(QtGui.QApplication.translate("plot_labels", "Title", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "xLabel").setText(QtGui.QApplication.translate("plot_labels", "X label", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "yLabel").setText(QtGui.QApplication.translate("plot_labels", "Y label", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.axId.setToolTip(QtGui.QApplication.translate("plot_labels", "Index of the active axes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.title.setToolTip(QtGui.QApplication.translate("plot_labels", "Title (associated to active axes)", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.titleSize.setToolTip(QtGui.QApplication.translate("plot_labels", "Title font size", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.xLabel.setToolTip(QtGui.QApplication.translate("plot_labels", "X axis title", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.xSize.setToolTip(QtGui.QApplication.translate("plot_labels", "X axis title font size", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.yLabel.setToolTip(QtGui.QApplication.translate("plot_labels", "Y axis title", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.ySize.setToolTip(QtGui.QApplication.translate("plot_labels", "Y axis title font size", - None,QtGui.QApplication.UnicodeUTF8)) - - def onAxesId(self, value): - """ Executed when axes index is modified. """ - if not self.skip: - self.skip = True - # UI control in some special plot cases - plt = Plot.getPlot() - if not plt: - self.updateUI() - self.skip = False - return - # UI control in most cases - self.form.axId.setMaximum(len(plt.axesList)) - if self.form.axId.value() >= len(plt.axesList): - self.form.axId.setValue(len(plt.axesList)-1) - # Send new control to Plot instance - plt.setActiveAxes(self.form.axId.value()) - self.updateUI() - self.skip = False - - def onLabels(self): - """ Executed when labels have been modified. """ - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - # Set labels - Plot.title(unicode(self.form.title.text())) - Plot.xlabel(unicode(self.form.xLabel.text())) - Plot.ylabel(unicode(self.form.yLabel.text())) - plt.update() - - def onFontSizes(self, value): - """ Executed when font sizes have been modified. """ - # Get apply environment - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - # Set font sizes - ax = plt.axes - ax.title.set_fontsize(self.form.titleSize.value()) - ax.xaxis.label.set_fontsize(self.form.xSize.value()) - ax.yaxis.label.set_fontsize(self.form.ySize.value()) - plt.update() - - def onMdiArea(self, subWin): - """ Executed when window is selected on mdi area. - @param subWin Selected window. - """ - plt = Plot.getPlot() - if plt != subWin: - self.updateUI() - - def updateUI(self): - """ Setup UI controls values if possible """ - plt = Plot.getPlot() - self.form.axId.setEnabled(bool(plt)) - self.form.title.setEnabled(bool(plt)) - self.form.titleSize.setEnabled(bool(plt)) - self.form.xLabel.setEnabled(bool(plt)) - self.form.xSize.setEnabled(bool(plt)) - self.form.yLabel.setEnabled(bool(plt)) - self.form.ySize.setEnabled(bool(plt)) - if not plt: - return - # Ensure that active axes is correct - index = min(self.form.axId.value(), len(plt.axesList)-1) - self.form.axId.setValue(index) - # Store data before starting changing it. - ax = plt.axes - t = ax.get_title() - x = ax.get_xlabel() - y = ax.get_ylabel() - tt = ax.title.get_fontsize() - xx = ax.xaxis.label.get_fontsize() - yy = ax.yaxis.label.get_fontsize() - # Set labels - self.form.title.setText(t) - self.form.xLabel.setText(x) - self.form.yLabel.setText(y) - # Set font sizes - self.form.titleSize.setValue(tt) - self.form.xSize.setValue(xx) - self.form.ySize.setValue(yy) + def __init__(self): + self.ui = Paths.modulePath() + "/plotLabels/TaskPanel.ui" + self.skip = False + + def accept(self): + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + form.title = self.widget(QtGui.QLineEdit, "title") + form.titleSize = self.widget(QtGui.QSpinBox, "titleSize") + form.xLabel = self.widget(QtGui.QLineEdit, "titleX") + form.xSize = self.widget(QtGui.QSpinBox, "xSize") + form.yLabel = self.widget(QtGui.QLineEdit, "titleY") + form.ySize = self.widget(QtGui.QSpinBox, "ySize") + self.form = form + self.retranslateUi() + # Look for active axes if can + axId = 0 + plt = Plot.getPlot() + if plt: + while plt.axes != plt.axesList[axId]: + axId = axId + 1 + form.axId.setValue(axId) + self.updateUI() + QtCore.QObject.connect(form.axId, + QtCore.SIGNAL('valueChanged(int)'), + self.onAxesId) + QtCore.QObject.connect(form.title, + QtCore.SIGNAL("editingFinished()"), + self.onLabels) + QtCore.QObject.connect(form.xLabel, + QtCore.SIGNAL("editingFinished()"), + self.onLabels) + QtCore.QObject.connect(form.yLabel, + QtCore.SIGNAL("editingFinished()"), + self.onLabels) + QtCore.QObject.connect(form.titleSize, + QtCore.SIGNAL("valueChanged(int)"), + self.onFontSizes) + QtCore.QObject.connect(form.xSize, + QtCore.SIGNAL("valueChanged(int)"), + self.onFontSizes) + QtCore.QObject.connect(form.ySize, + QtCore.SIGNAL("valueChanged(int)"), + self.onFontSizes) + QtCore.QObject.connect( + Plot.getMdiArea(), + QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"), + self.onMdiArea) + return False + + def getMainWindow(self): + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def widget(self, class_id, name): + """Return the selected widget. + + Keyword arguments: + class_id -- Class identifier + name -- Name of the widget + """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + return form.findChild(class_id, name) + + def retranslateUi(self): + """ Set the user interface locale strings. + """ + self.form.setWindowTitle(QtGui.QApplication.translate( + "plot_labels", + "Set labels", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "axesLabel").setText( + QtGui.QApplication.translate("plot_labels", + "Active axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "titleLabel").setText( + QtGui.QApplication.translate("plot_labels", + "Title", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "xLabel").setText( + QtGui.QApplication.translate("plot_labels", + "X label", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "yLabel").setText( + QtGui.QApplication.translate("plot_labels", + "Y label", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "axesIndex").setToolTip(QtGui.QApplication.translate( + "plot_labels", + "Index of the active axes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLineEdit, "title").setToolTip( + QtGui.QApplication.translate( + "plot_labels", + "Title (associated to active axes)", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "titleSize").setToolTip( + QtGui.QApplication.translate( + "plot_labels", + "Title font size", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLineEdit, "titleX").setToolTip( + QtGui.QApplication.translate( + "plot_labels", + "X axis title", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "xSize").setToolTip( + QtGui.QApplication.translate( + "plot_labels", + "X axis title font size", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLineEdit, "titleY").setToolTip( + QtGui.QApplication.translate( + "plot_labels", + "Y axis title", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "ySize").setToolTip( + QtGui.QApplication.translate( + "plot_labels", + "Y axis title font size", + None, + QtGui.QApplication.UnicodeUTF8)) + + def onAxesId(self, value): + """ Executed when axes index is modified. """ + if not self.skip: + self.skip = True + # No active plot case + plt = Plot.getPlot() + if not plt: + self.updateUI() + self.skip = False + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + + form.axId.setMaximum(len(plt.axesList)) + if form.axId.value() >= len(plt.axesList): + form.axId.setValue(len(plt.axesList) - 1) + # Send new control to Plot instance + plt.setActiveAxes(form.axId.value()) + self.updateUI() + self.skip = False + + def onLabels(self): + """ Executed when labels have been modified. """ + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.title = self.widget(QtGui.QLineEdit, "title") + form.xLabel = self.widget(QtGui.QLineEdit, "titleX") + form.yLabel = self.widget(QtGui.QLineEdit, "titleY") + + Plot.title(unicode(form.title.text())) + Plot.xlabel(unicode(form.xLabel.text())) + Plot.ylabel(unicode(form.yLabel.text())) + plt.update() + + def onFontSizes(self, value): + """ Executed when font sizes have been modified. """ + # Get apply environment + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.titleSize = self.widget(QtGui.QSpinBox, "titleSize") + form.xSize = self.widget(QtGui.QSpinBox, "xSize") + form.ySize = self.widget(QtGui.QSpinBox, "ySize") + + ax = plt.axes + ax.title.set_fontsize(form.titleSize.value()) + ax.xaxis.label.set_fontsize(form.xSize.value()) + ax.yaxis.label.set_fontsize(form.ySize.value()) + plt.update() + + def onMdiArea(self, subWin): + """ Executed when window is selected on mdi area. + + Keyword arguments: + subWin -- Selected window. + """ + plt = Plot.getPlot() + if plt != subWin: + self.updateUI() + + def updateUI(self): + """ Setup UI controls values if possible """ + # Get again all the subwidgets (to avoid PySide Pitfalls) + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.axId = self.widget(QtGui.QSpinBox, "axesIndex") + form.title = self.widget(QtGui.QLineEdit, "title") + form.titleSize = self.widget(QtGui.QSpinBox, "titleSize") + form.xLabel = self.widget(QtGui.QLineEdit, "titleX") + form.xSize = self.widget(QtGui.QSpinBox, "xSize") + form.yLabel = self.widget(QtGui.QLineEdit, "titleY") + form.ySize = self.widget(QtGui.QSpinBox, "ySize") + + plt = Plot.getPlot() + form.axId.setEnabled(bool(plt)) + form.title.setEnabled(bool(plt)) + form.titleSize.setEnabled(bool(plt)) + form.xLabel.setEnabled(bool(plt)) + form.xSize.setEnabled(bool(plt)) + form.yLabel.setEnabled(bool(plt)) + form.ySize.setEnabled(bool(plt)) + if not plt: + return + # Ensure that active axes is correct + index = min(form.axId.value(), len(plt.axesList) - 1) + form.axId.setValue(index) + # Store data before starting changing it. + + ax = plt.axes + t = ax.get_title() + x = ax.get_xlabel() + y = ax.get_ylabel() + tt = ax.title.get_fontsize() + xx = ax.xaxis.label.get_fontsize() + yy = ax.yaxis.label.get_fontsize() + # Set labels + form.title.setText(t) + form.xLabel.setText(x) + form.yLabel.setText(y) + # Set font sizes + form.titleSize.setValue(tt) + form.xSize.setValue(xx) + form.ySize.setValue(yy) + def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Plot/plotLabels/__init__.py b/src/Mod/Plot/plotLabels/__init__.py index 24058d7a93ee..6a97f58b26af 100644 --- a/src/Mod/Plot/plotLabels/__init__.py +++ b/src/Mod/Plot/plotLabels/__init__.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,16 +21,9 @@ #* * #*************************************************************************** -# FreeCAD modules -import FreeCAD -import FreeCADGui - -# Qt libraries -from PyQt4 import QtGui,QtCore - -# Main object import TaskPanel + def load(): - """ Loads the tool """ - TaskPanel.createTask() + """Load the tool""" + TaskPanel.createTask() diff --git a/src/Mod/Plot/plotPositions/TaskPanel.py b/src/Mod/Plot/plotPositions/TaskPanel.py index cc082489475a..9ff0bfebfcfc 100644 --- a/src/Mod/Plot/plotPositions/TaskPanel.py +++ b/src/Mod/Plot/plotPositions/TaskPanel.py @@ -1,234 +1,301 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* 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 Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* 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 Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * #* License along with this program; if not, write to the Free Software * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * +#* USA * +#* * #*************************************************************************** -# FreeCAD modules import FreeCAD as App import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module + +from PySide import QtGui, QtCore + import Plot from plotUtils import Paths + class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/plotPositions/TaskPanel.ui" - self.skip = False - self.item = 0 - self.names = [] - self.objs = [] - self.plt = None - - def accept(self): - return True - - def reject(self): - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.items = form.findChild(QtGui.QListWidget, "items") - form.x = form.findChild(QtGui.QDoubleSpinBox, "x") - form.y = form.findChild(QtGui.QDoubleSpinBox, "y") - form.s = form.findChild(QtGui.QDoubleSpinBox, "size") - self.form = form - self.retranslateUi() - self.updateUI() - QtCore.QObject.connect(form.items, QtCore.SIGNAL("currentRowChanged(int)"),self.onItem) - QtCore.QObject.connect(form.x, QtCore.SIGNAL("valueChanged(double)"),self.onData) - QtCore.QObject.connect(form.y, QtCore.SIGNAL("valueChanged(double)"),self.onData) - QtCore.QObject.connect(form.s, QtCore.SIGNAL("valueChanged(double)"),self.onData) - QtCore.QObject.connect(Plot.getMdiArea(),QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"),self.onMdiArea) - return False - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(QtGui.QApplication.translate("plot_positions", "Set positions and sizes", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "posLabel").setText(QtGui.QApplication.translate("plot_positions", "Position", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "sizeLabel").setText(QtGui.QApplication.translate("plot_positions", "Size", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.items.setToolTip(QtGui.QApplication.translate("plot_positions", "List of modificable items", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.x.setToolTip(QtGui.QApplication.translate("plot_positions", "X item position", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.y.setToolTip(QtGui.QApplication.translate("plot_positions", "Y item position", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.s.setToolTip(QtGui.QApplication.translate("plot_positions", "Item size", - None,QtGui.QApplication.UnicodeUTF8)) - - def onItem(self, row): - """ Executed when selected item is modified. """ - # Get selected item - self.item = row - # Call to update - self.updateUI() - - def onData(self, value): - """ Executed when selected item data is modified. """ - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - if not self.skip: - self.skip = True - name = self.names[self.item] - obj = self.objs[self.item] - x = self.form.x.value() - y = self.form.y.value() - s = self.form.s.value() - # x/y labels only have one position control - if name.find('x label') >= 0: - self.form.y.setValue(x) - elif name.find('y label') >= 0: - self.form.x.setValue(y) - # title and labels only have one size control - if name.find('title') >= 0 or name.find('label') >= 0: - obj.set_position((x,y)) - obj.set_size(s) - # legend have all controls - else: - Plot.legend(plt.legend, (x,y), s) - plt.update() - self.skip = False - - def onMdiArea(self, subWin): - """ Executed when window is selected on mdi area. - @param subWin Selected window. - """ - plt = Plot.getPlot() - if plt != subWin: - self.updateUI() - - def updateUI(self): - """ Setup UI controls values if possible """ - plt = Plot.getPlot() - self.form.items.setEnabled(bool(plt)) - self.form.x.setEnabled(bool(plt)) - self.form.y.setEnabled(bool(plt)) - self.form.s.setEnabled(bool(plt)) - if not plt: - self.plt = plt - self.form.items.clear() - return - # Refill items list only if Plot instance have been changed - if self.plt != plt: - self.plt = plt - self.plt.update() # Update plot in order to put legend in correct place - self.setList() - # Get data for controls - name = self.names[self.item] - obj = self.objs[self.item] - if name.find('title') >= 0 or name.find('label') >= 0: - p = obj.get_position() - x = p[0] - y = p[1] - s = obj.get_size() - if name.find('x label') >= 0: - self.form.y.setEnabled(False) - self.form.y.setValue(x) - elif name.find('y label') >= 0: - self.form.x.setEnabled(False) - self.form.x.setValue(y) - else: - x = plt.legPos[0] - y = plt.legPos[1] - s = obj.get_texts()[-1].get_fontsize() - # Send it to controls - self.form.x.setValue(x) - self.form.y.setValue(y) - self.form.s.setValue(s) - - def setList(self): - """ Setup UI controls values if possible """ - # Clear lists - self.names = [] - self.objs = [] - # Fill lists with available objects - if self.plt: - # Axes data - for i in range(0,len(self.plt.axesList)): - ax = self.plt.axesList[i] - # Each axes have title, xaxis and yaxis - self.names.append('title (axes %d)' % (i)) - self.objs.append(ax.title) - self.names.append('x label (axes %d)' % (i)) - self.objs.append(ax.xaxis.get_label()) - self.names.append('y label (axes %d)' % (i)) - self.objs.append(ax.yaxis.get_label()) - # Legend if exist - ax = self.plt.axesList[-1] - if ax.legend_: - self.names.append('legend') - self.objs.append(ax.legend_) - # Send list to widget - self.form.items.clear() - for name in self.names: - self.form.items.addItem(name) - # Ensure that selected item is correct - if self.item >= len(self.names): - self.item = len(self.names)-1 - self.form.items.setCurrentIndex(self.item) + def __init__(self): + self.ui = Paths.modulePath() + "/plotPositions/TaskPanel.ui" + self.skip = False + self.item = 0 + self.names = [] + self.objs = [] + self.plt = None + + def accept(self): + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.items = self.widget(QtGui.QListWidget, "items") + form.x = self.widget(QtGui.QDoubleSpinBox, "x") + form.y = self.widget(QtGui.QDoubleSpinBox, "y") + form.s = self.widget(QtGui.QDoubleSpinBox, "size") + self.form = form + self.retranslateUi() + self.updateUI() + QtCore.QObject.connect( + form.items, + QtCore.SIGNAL("currentRowChanged(int)"), + self.onItem) + QtCore.QObject.connect( + form.x, + QtCore.SIGNAL("valueChanged(double)"), + self.onData) + QtCore.QObject.connect( + form.y, + QtCore.SIGNAL("valueChanged(double)"), + self.onData) + QtCore.QObject.connect( + form.s, + QtCore.SIGNAL("valueChanged(double)"), + self.onData) + QtCore.QObject.connect( + Plot.getMdiArea(), + QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"), + self.onMdiArea) + return False + + def getMainWindow(self): + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def widget(self, class_id, name): + """Return the selected widget. + + Keyword arguments: + class_id -- Class identifier + name -- Name of the widget + """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + return form.findChild(class_id, name) + + def retranslateUi(self): + """Set the user interface locale strings.""" + self.form.setWindowTitle(QtGui.QApplication.translate( + "plot_positions", + "Set positions and sizes", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "posLabel").setText( + QtGui.QApplication.translate( + "plot_positions", + "Position", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "sizeLabel").setText( + QtGui.QApplication.translate( + "plot_positions", + "Size", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QListWidget, "items").setToolTip( + QtGui.QApplication.translate( + "plot_positions", + "List of modificable items", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QDoubleSpinBox, "x").setToolTip( + QtGui.QApplication.translate( + "plot_positions", + "X item position", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QDoubleSpinBox, "y").setToolTip( + QtGui.QApplication.translate( + "plot_positions", + "Y item position", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QDoubleSpinBox, "size").setToolTip( + QtGui.QApplication.translate( + "plot_positions", + "Item size", + None, + QtGui.QApplication.UnicodeUTF8)) + + def onItem(self, row): + """ Executed when selected item is modified. """ + self.item = row + self.updateUI() + + def onData(self, value): + """ Executed when selected item data is modified. """ + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.items = self.widget(QtGui.QListWidget, "items") + form.x = self.widget(QtGui.QDoubleSpinBox, "x") + form.y = self.widget(QtGui.QDoubleSpinBox, "y") + form.s = self.widget(QtGui.QDoubleSpinBox, "size") + if not self.skip: + self.skip = True + name = self.names[self.item] + obj = self.objs[self.item] + x = form.x.value() + y = form.y.value() + s = form.s.value() + # x/y labels only have one position control + if name.find('x label') >= 0: + form.y.setValue(x) + elif name.find('y label') >= 0: + form.x.setValue(y) + # title and labels only have one size control + if name.find('title') >= 0 or name.find('label') >= 0: + obj.set_position((x, y)) + obj.set_size(s) + # legend have all controls + else: + Plot.legend(plt.legend, (x, y), s) + plt.update() + self.skip = False + + def onMdiArea(self, subWin): + """Executed when a new window is selected on the mdi area. + + Keyword arguments: + subWin -- Selected window. + """ + plt = Plot.getPlot() + if plt != subWin: + self.updateUI() + + def updateUI(self): + """Setup the UI control values if it is possible.""" + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.items = self.widget(QtGui.QListWidget, "items") + form.x = self.widget(QtGui.QDoubleSpinBox, "x") + form.y = self.widget(QtGui.QDoubleSpinBox, "y") + form.s = self.widget(QtGui.QDoubleSpinBox, "size") + plt = Plot.getPlot() + form.items.setEnabled(bool(plt)) + form.x.setEnabled(bool(plt)) + form.y.setEnabled(bool(plt)) + form.s.setEnabled(bool(plt)) + if not plt: + self.plt = plt + form.items.clear() + return + # Refill items list only if Plot instance have been changed + if self.plt != plt: + self.plt = plt + self.plt.update() + self.setList() + # Get data for controls + name = self.names[self.item] + obj = self.objs[self.item] + if name.find('title') >= 0 or name.find('label') >= 0: + p = obj.get_position() + x = p[0] + y = p[1] + s = obj.get_size() + if name.find('x label') >= 0: + form.y.setEnabled(False) + form.y.setValue(x) + elif name.find('y label') >= 0: + form.x.setEnabled(False) + form.x.setValue(y) + else: + x = plt.legPos[0] + y = plt.legPos[1] + s = obj.get_texts()[-1].get_fontsize() + # Send it to controls + form.x.setValue(x) + form.y.setValue(y) + form.s.setValue(s) + + def setList(self): + """ Setup UI controls values if possible """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.items = self.widget(QtGui.QListWidget, "items") + form.x = self.widget(QtGui.QDoubleSpinBox, "x") + form.y = self.widget(QtGui.QDoubleSpinBox, "y") + form.s = self.widget(QtGui.QDoubleSpinBox, "size") + # Clear lists + self.names = [] + self.objs = [] + # Fill lists with available objects + if self.plt: + # Axes data + for i in range(0, len(self.plt.axesList)): + ax = self.plt.axesList[i] + # Each axes have title, xaxis and yaxis + self.names.append('title (axes {})'.format(i)) + self.objs.append(ax.title) + self.names.append('x label (axes {})'.format(i)) + self.objs.append(ax.xaxis.get_label()) + self.names.append('y label (axes {})'.format(i)) + self.objs.append(ax.yaxis.get_label()) + # Legend if exist + ax = self.plt.axesList[-1] + if ax.legend_: + self.names.append('legend') + self.objs.append(ax.legend_) + # Send list to widget + form.items.clear() + for name in self.names: + form.items.addItem(name) + # Ensure that selected item is correct + if self.item >= len(self.names): + self.item = len(self.names) - 1 + form.items.setCurrentIndex(self.item) + def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Plot/plotPositions/__init__.py b/src/Mod/Plot/plotPositions/__init__.py index 24058d7a93ee..6a97f58b26af 100644 --- a/src/Mod/Plot/plotPositions/__init__.py +++ b/src/Mod/Plot/plotPositions/__init__.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,16 +21,9 @@ #* * #*************************************************************************** -# FreeCAD modules -import FreeCAD -import FreeCADGui - -# Qt libraries -from PyQt4 import QtGui,QtCore - -# Main object import TaskPanel + def load(): - """ Loads the tool """ - TaskPanel.createTask() + """Load the tool""" + TaskPanel.createTask() diff --git a/src/Mod/Plot/plotSave/TaskPanel.py b/src/Mod/Plot/plotSave/TaskPanel.py index 1ee042de1399..2ba6d936c835 100644 --- a/src/Mod/Plot/plotSave/TaskPanel.py +++ b/src/Mod/Plot/plotSave/TaskPanel.py @@ -1,163 +1,235 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* 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 Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* 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 Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * #* License along with this program; if not, write to the Free Software * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * +#* USA * +#* * #*************************************************************************** import os -# FreeCAD modules + import FreeCAD as App import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module + +from PySide import QtGui, QtCore + import Plot from plotUtils import Paths + class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/plotSave/TaskPanel.ui" - - def accept(self): - plt = Plot.getPlot() - if not plt: - msg = QtGui.QApplication.translate("plot_console", "Plot document must be selected in order to save it", - None,QtGui.QApplication.UnicodeUTF8) - App.Console.PrintError(msg+"\n") - return False - path = unicode(self.form.path.text()) - size = (self.form.sizeX.value(), self.form.sizeY.value()) - dpi = self.form.dpi.value() - Plot.save(path, size, dpi) - return True - - def reject(self): - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.path = form.findChild(QtGui.QLineEdit, "path") - form.pathButton = form.findChild(QtGui.QPushButton, "pathButton") - form.sizeX = form.findChild(QtGui.QDoubleSpinBox, "sizeX") - form.sizeY = form.findChild(QtGui.QDoubleSpinBox, "sizeY") - form.dpi = form.findChild(QtGui.QSpinBox, "dpi") - self.form = form - self.retranslateUi() - QtCore.QObject.connect(form.pathButton,QtCore.SIGNAL("pressed()"),self.onPathButton) - QtCore.QObject.connect(Plot.getMdiArea(),QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"),self.onMdiArea) - home = os.getenv('USERPROFILE') or os.getenv('HOME') - form.path.setText(os.path.join(home,"plot.png")) - self.updateUI() - return False - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(QtGui.QApplication.translate("plot_save", "Save figure", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "sizeLabel").setText(QtGui.QApplication.translate("plot_save", "Inches", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "dpiLabel").setText(QtGui.QApplication.translate("plot_save", "Dots per Inch", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.path.setToolTip(QtGui.QApplication.translate("plot_save", "Output image file path", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.pathButton.setToolTip(QtGui.QApplication.translate("plot_save", "Show a file selection dialog", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.sizeX.setToolTip(QtGui.QApplication.translate("plot_save", "X image size", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.sizeY.setToolTip(QtGui.QApplication.translate("plot_save", "Y image size", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.dpi.setToolTip(QtGui.QApplication.translate("plot_save", "Dots per point, with size will define output image resolution", - None,QtGui.QApplication.UnicodeUTF8)) - - def updateUI(self): - """ Setup UI controls values if possible """ - plt = Plot.getPlot() - self.form.path.setEnabled(bool(plt)) - self.form.pathButton.setEnabled(bool(plt)) - self.form.sizeX.setEnabled(bool(plt)) - self.form.sizeY.setEnabled(bool(plt)) - self.form.dpi.setEnabled(bool(plt)) - if not plt: - return - fig = plt.fig - size = fig.get_size_inches() - dpi = fig.get_dpi() - self.form.sizeX.setValue(size[0]) - self.form.sizeY.setValue(size[1]) - self.form.dpi.setValue(dpi) - - def onPathButton(self): - """ Executed when path button is pressed. - """ - path = self.form.path.text() - file_choices = "Portable Network Graphics (*.png)|*.png;;Portable Document Format (*.pdf)|*.pdf;;PostScript (*.ps)|*.ps;;Encapsulated PostScript (*.eps)|*.eps" - path = QtGui.QFileDialog.getSaveFileName(None, 'Save figure', path, file_choices) - if path: - self.form.path.setText(path) - - def onMdiArea(self, subWin): - """ Executed when window is selected on mdi area. - @param subWin Selected window. - """ - plt = Plot.getPlot() - if plt != subWin: - self.updateUI() + def __init__(self): + self.ui = Paths.modulePath() + "/plotSave/TaskPanel.ui" + + def accept(self): + plt = Plot.getPlot() + if not plt: + msg = QtGui.QApplication.translate( + "plot_console", + "Plot document must be selected in order to save it", + None, + QtGui.QApplication.UnicodeUTF8) + App.Console.PrintError(msg + "\n") + return False + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.path = self.widget(QtGui.QLineEdit, "path") + form.sizeX = self.widget(QtGui.QDoubleSpinBox, "sizeX") + form.sizeY = self.widget(QtGui.QDoubleSpinBox, "sizeY") + form.dpi = self.widget(QtGui.QSpinBox, "dpi") + path = unicode(form.path.text()) + size = (form.sizeX.value(), form.sizeY.value()) + dpi = form.dpi.value() + Plot.save(path, size, dpi) + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.path = self.widget(QtGui.QLineEdit, "path") + form.pathButton = self.widget(QtGui.QPushButton, "pathButton") + form.sizeX = self.widget(QtGui.QDoubleSpinBox, "sizeX") + form.sizeY = self.widget(QtGui.QDoubleSpinBox, "sizeY") + form.dpi = self.widget(QtGui.QSpinBox, "dpi") + self.form = form + self.retranslateUi() + QtCore.QObject.connect( + form.pathButton, + QtCore.SIGNAL("pressed()"), + self.onPathButton) + QtCore.QObject.connect( + Plot.getMdiArea(), + QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"), + self.onMdiArea) + home = os.getenv('USERPROFILE') or os.getenv('HOME') + form.path.setText(os.path.join(home, "plot.png")) + self.updateUI() + return False + + def getMainWindow(self): + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def widget(self, class_id, name): + """Return the selected widget. + + Keyword arguments: + class_id -- Class identifier + name -- Name of the widget + """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + return form.findChild(class_id, name) + + def retranslateUi(self): + """Set the user interface locale strings.""" + self.form.setWindowTitle(QtGui.QApplication.translate( + "plot_save", + "Save figure", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "sizeLabel").setText( + QtGui.QApplication.translate( + "plot_save", + "Inches", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "dpiLabel").setText( + QtGui.QApplication.translate( + "plot_save", + "Dots per Inch", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLineEdit, "path").setToolTip( + QtGui.QApplication.translate( + "plot_save", + "Output image file path", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QPushButton, "pathButton").setToolTip( + QtGui.QApplication.translate( + "plot_save", + "Show a file selection dialog", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QDoubleSpinBox, "sizeX").setToolTip( + QtGui.QApplication.translate( + "plot_save", + "X image size", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QDoubleSpinBox, "sizeY").setToolTip( + QtGui.QApplication.translate( + "plot_save", + "Y image size", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "dpi").setToolTip( + QtGui.QApplication.translate( + "plot_save", + "Dots per point, with size will define output image" + " resolution", + None, + QtGui.QApplication.UnicodeUTF8)) + + def updateUI(self): + """ Setup UI controls values if possible """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.path = self.widget(QtGui.QLineEdit, "path") + form.pathButton = self.widget(QtGui.QPushButton, "pathButton") + form.sizeX = self.widget(QtGui.QDoubleSpinBox, "sizeX") + form.sizeY = self.widget(QtGui.QDoubleSpinBox, "sizeY") + form.dpi = self.widget(QtGui.QSpinBox, "dpi") + plt = Plot.getPlot() + form.path.setEnabled(bool(plt)) + form.pathButton.setEnabled(bool(plt)) + form.sizeX.setEnabled(bool(plt)) + form.sizeY.setEnabled(bool(plt)) + form.dpi.setEnabled(bool(plt)) + if not plt: + return + fig = plt.fig + size = fig.get_size_inches() + dpi = fig.get_dpi() + form.sizeX.setValue(size[0]) + form.sizeY.setValue(size[1]) + form.dpi.setValue(dpi) + + def onPathButton(self): + """Executed when the path selection button is pressed.""" + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.path = self.widget(QtGui.QLineEdit, "path") + path = form.path.text() + file_choices = ("Portable Network Graphics (*.png)|*.png;;" + "Portable Document Format (*.pdf)|*.pdf;;" + "PostScript (*.ps)|*.ps;;" + "Encapsulated PostScript (*.eps)|*.eps") + path = QtGui.QFileDialog.getSaveFileName(None, + 'Save figure', + path, + file_choices) + if path: + form.path.setText(path) + + def onMdiArea(self, subWin): + """Executed when a new window is selected on the mdi area. + + Keyword arguments: + subWin -- Selected window. + """ + plt = Plot.getPlot() + if plt != subWin: + self.updateUI() + def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Plot/plotSave/__init__.py b/src/Mod/Plot/plotSave/__init__.py index 24058d7a93ee..6a97f58b26af 100644 --- a/src/Mod/Plot/plotSave/__init__.py +++ b/src/Mod/Plot/plotSave/__init__.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,16 +21,9 @@ #* * #*************************************************************************** -# FreeCAD modules -import FreeCAD -import FreeCADGui - -# Qt libraries -from PyQt4 import QtGui,QtCore - -# Main object import TaskPanel + def load(): - """ Loads the tool """ - TaskPanel.createTask() + """Load the tool""" + TaskPanel.createTask() diff --git a/src/Mod/Plot/plotSeries/TaskPanel.py b/src/Mod/Plot/plotSeries/TaskPanel.py index 381d41b89ef7..f32b8aeacc71 100644 --- a/src/Mod/Plot/plotSeries/TaskPanel.py +++ b/src/Mod/Plot/plotSeries/TaskPanel.py @@ -1,332 +1,462 @@ #*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * #* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* 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 Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* 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 Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * #* License along with this program; if not, write to the Free Software * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * +#* USA * +#* * #*************************************************************************** -# FreeCAD modules import FreeCAD as App import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module + +from PySide import QtGui, QtCore + import Plot from plotUtils import Paths -# matplotlib + import matplotlib from matplotlib.lines import Line2D import matplotlib.colors as Colors + class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/plotSeries/TaskPanel.ui" - self.skip = False - self.item = 0 - self.plt = None - - def accept(self): - return True - - def reject(self): - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.items = form.findChild(QtGui.QListWidget, "items") - form.label = form.findChild(QtGui.QLineEdit, "label") - form.isLabel = form.findChild(QtGui.QCheckBox, "isLabel") - form.style = form.findChild(QtGui.QComboBox, "lineStyle") - form.marker = form.findChild(QtGui.QComboBox, "markers") - form.width = form.findChild(QtGui.QDoubleSpinBox, "lineWidth") - form.size = form.findChild(QtGui.QSpinBox, "markerSize") - form.color = form.findChild(QtGui.QPushButton, "color") - form.remove = form.findChild(QtGui.QPushButton, "remove") - self.form = form - self.retranslateUi() - self.fillStyles() - self.updateUI() - QtCore.QObject.connect(form.items, QtCore.SIGNAL("currentRowChanged(int)"),self.onItem) - QtCore.QObject.connect(form.label, QtCore.SIGNAL("editingFinished()"),self.onData) - QtCore.QObject.connect(form.isLabel,QtCore.SIGNAL("stateChanged(int)"),self.onData) - QtCore.QObject.connect(form.style, QtCore.SIGNAL("currentIndexChanged(int)"),self.onData) - QtCore.QObject.connect(form.marker, QtCore.SIGNAL("currentIndexChanged(int)"),self.onData) - QtCore.QObject.connect(form.width, QtCore.SIGNAL("valueChanged(double)"),self.onData) - QtCore.QObject.connect(form.size, QtCore.SIGNAL("valueChanged(int)"),self.onData) - QtCore.QObject.connect(form.color, QtCore.SIGNAL("pressed()"),self.onColor) - QtCore.QObject.connect(form.remove, QtCore.SIGNAL("pressed()"),self.onRemove) - QtCore.QObject.connect(Plot.getMdiArea(),QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"),self.onMdiArea) - return False - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(QtGui.QApplication.translate("plot_series", "Configure series", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.isLabel.setText(QtGui.QApplication.translate("plot_series", "No label", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.remove.setText(QtGui.QApplication.translate("plot_series", "Remove serie", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "styleLabel").setText(QtGui.QApplication.translate("plot_series", "Line style", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.findChild(QtGui.QLabel, "markerLabel").setText(QtGui.QApplication.translate("plot_series", "Marker", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.items.setToolTip(QtGui.QApplication.translate("plot_series", "List of available series", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.label.setToolTip(QtGui.QApplication.translate("plot_series", "Line title", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.isLabel.setToolTip(QtGui.QApplication.translate("plot_series", "If checked serie will not be considered for legend", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.style.setToolTip(QtGui.QApplication.translate("plot_series", "Line style", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.marker.setToolTip(QtGui.QApplication.translate("plot_series", "Marker style", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.width.setToolTip(QtGui.QApplication.translate("plot_series", "Line width", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.size.setToolTip(QtGui.QApplication.translate("plot_series", "Marker size", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.color.setToolTip(QtGui.QApplication.translate("plot_series", "Line and marker color", - None,QtGui.QApplication.UnicodeUTF8)) - self.form.remove.setToolTip(QtGui.QApplication.translate("plot_series", "Removes this serie", - None,QtGui.QApplication.UnicodeUTF8)) - - def fillStyles(self): - """ Fill style combo boxes. """ - # Line styles - linestyles = Line2D.lineStyles.keys() - for i in range(0,len(linestyles)): - style = linestyles[i] - string = "\'" + str(style) + "\' (" + Line2D.lineStyles[style] + ")" - self.form.style.addItem(string) - # Markers - markers = Line2D.markers.keys() - for i in range(0,len(markers)): - marker = markers[i] - string = "\'" + str(marker) + "\' (" + Line2D.markers[marker] + ")" - self.form.marker.addItem(string) - - def onItem(self, row): - """ Executed when selected item is modified. """ - if not self.skip: - self.skip = True - # Get selected item - self.item = row - # Call to update - self.updateUI() - self.skip = False - - def onData(self): - """ Executed when selected item data is modified. """ - if not self.skip: - self.skip = True - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - # Ensure that selected serie exist - if self.item >= len(Plot.series()): - self.updateUI() - return - # Set label - serie = Plot.series()[self.item] - if(self.form.isLabel.isChecked()): - serie.name = None - self.form.label.setEnabled(False) - else: - serie.name = self.form.label.text() - self.form.label.setEnabled(True) - # Set line style and marker - style = self.form.style.currentIndex() - linestyles = Line2D.lineStyles.keys() - serie.line.set_linestyle(linestyles[style]) - marker = self.form.marker.currentIndex() - markers = Line2D.markers.keys() - serie.line.set_marker(markers[marker]) - # Set line width and marker size - serie.line.set_linewidth(self.form.width.value()) - serie.line.set_markersize(self.form.size.value()) - plt.update() - # Regenerate series labels - self.setList() - self.skip = False - - def onColor(self): - """ Executed when color pallete is requested. """ - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - # Ensure that selected serie exist - if self.item >= len(Plot.series()): - self.updateUI() - return - # Show widget to select color - col = QtGui.QColorDialog.getColor() - # Send color to widget and serie - if col.isValid(): - serie = plt.series[self.item] - self.form.color.setStyleSheet("background-color: rgb(%d, %d, %d);" % (col.red(), - col.green(), col.blue())) - serie.line.set_color((col.redF(), col.greenF(), col.blueF())) - plt.update() - - def onRemove(self): - """ Executed when data serie must be removed. """ - plt = Plot.getPlot() - if not plt: - self.updateUI() - return - # Ensure that selected serie exist - if self.item >= len(Plot.series()): - self.updateUI() - return - # Remove serie - Plot.removeSerie(self.item) - self.setList() - self.updateUI() - plt.update() - - def onMdiArea(self, subWin): - """ Executed when window is selected on mdi area. - @param subWin Selected window. - """ - plt = Plot.getPlot() - if plt != subWin: - self.updateUI() - - def updateUI(self): - """ Setup UI controls values if possible """ - plt = Plot.getPlot() - self.form.items.setEnabled(bool(plt)) - self.form.label.setEnabled(bool(plt)) - self.form.isLabel.setEnabled(bool(plt)) - self.form.style.setEnabled(bool(plt)) - self.form.marker.setEnabled(bool(plt)) - self.form.width.setEnabled(bool(plt)) - self.form.size.setEnabled(bool(plt)) - self.form.color.setEnabled(bool(plt)) - self.form.remove.setEnabled(bool(plt)) - if not plt: - self.plt = plt - self.form.items.clear() - return - self.skip = True - # Refill list - if self.plt != plt or len(Plot.series()) != self.form.items.count(): - self.plt = plt - self.setList() - # Ensure that have series - if not len(Plot.series()): - self.form.label.setEnabled(False) - self.form.isLabel.setEnabled(False) - self.form.style.setEnabled(False) - self.form.marker.setEnabled(False) - self.form.width.setEnabled(False) - self.form.size.setEnabled(False) - self.form.color.setEnabled(False) - self.form.remove.setEnabled(False) - return - # Set label - serie = Plot.series()[self.item] - if serie.name == None: - self.form.isLabel.setChecked(True) - self.form.label.setEnabled(False) - self.form.label.setText("") - else: - self.form.isLabel.setChecked(False) - self.form.label.setText(serie.name) - # Set line style and marker - self.form.style.setCurrentIndex(0) - linestyles = Line2D.lineStyles.keys() - for i in range(0,len(linestyles)): - style = linestyles[i] - if style == serie.line.get_linestyle(): - self.form.style.setCurrentIndex(i) - self.form.marker.setCurrentIndex(0) - markers = Line2D.markers.keys() - for i in range(0,len(markers)): - marker = markers[i] - if marker == serie.line.get_marker(): - self.form.marker.setCurrentIndex(i) - # Set line width and marker size - self.form.width.setValue(serie.line.get_linewidth()) - self.form.size.setValue(serie.line.get_markersize()) - # Set color - color = Colors.colorConverter.to_rgb(serie.line.get_color()) - self.form.color.setStyleSheet("background-color: rgb(%d, %d, %d);" % (int(color[0]*255), - int(color[1]*255), int(color[2]*255))) - self.skip = False - - def setList(self): - """ Setup UI controls values if possible """ - self.form.items.clear() - series = Plot.series() - for i in range(0,len(series)): - serie = series[i] - string = 'serie ' + str(i) + ': ' - if serie.name == None: - string = string + '\"No label\"' - else: - string = string + serie.name - self.form.items.addItem(string) - # Ensure that selected item is correct - if len(series) and self.item >= len(series): - self.item = len(series)-1 - self.form.items.setCurrentIndex(self.item) + def __init__(self): + self.ui = Paths.modulePath() + "/plotSeries/TaskPanel.ui" + self.skip = False + self.item = 0 + self.plt = None + + def accept(self): + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.items = self.widget(QtGui.QListWidget, "items") + form.label = self.widget(QtGui.QLineEdit, "label") + form.isLabel = self.widget(QtGui.QCheckBox, "isLabel") + form.style = self.widget(QtGui.QComboBox, "lineStyle") + form.marker = self.widget(QtGui.QComboBox, "markers") + form.width = self.widget(QtGui.QDoubleSpinBox, "lineWidth") + form.size = self.widget(QtGui.QSpinBox, "markerSize") + form.color = self.widget(QtGui.QPushButton, "color") + form.remove = self.widget(QtGui.QPushButton, "remove") + self.form = form + self.retranslateUi() + self.fillStyles() + self.updateUI() + QtCore.QObject.connect( + form.items, + QtCore.SIGNAL("currentRowChanged(int)"), + self.onItem) + QtCore.QObject.connect( + form.label, + QtCore.SIGNAL("editingFinished()"), + self.onData) + QtCore.QObject.connect( + form.isLabel, + QtCore.SIGNAL("stateChanged(int)"), + self.onData) + QtCore.QObject.connect( + form.style, + QtCore.SIGNAL("currentIndexChanged(int)"), + self.onData) + QtCore.QObject.connect( + form.marker, + QtCore.SIGNAL("currentIndexChanged(int)"), + self.onData) + QtCore.QObject.connect( + form.width, + QtCore.SIGNAL("valueChanged(double)"), + self.onData) + QtCore.QObject.connect( + form.size, + QtCore.SIGNAL("valueChanged(int)"), + self.onData) + QtCore.QObject.connect( + form.color, + QtCore.SIGNAL("pressed()"), + self.onColor) + QtCore.QObject.connect( + form.remove, + QtCore.SIGNAL("pressed()"), + self.onRemove) + QtCore.QObject.connect( + Plot.getMdiArea(), + QtCore.SIGNAL("subWindowActivated(QMdiSubWindow*)"), + self.onMdiArea) + return False + + def getMainWindow(self): + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def widget(self, class_id, name): + """Return the selected widget. + + Keyword arguments: + class_id -- Class identifier + name -- Name of the widget + """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + return form.findChild(class_id, name) + + def retranslateUi(self): + """Set the user interface locale strings.""" + self.form.setWindowTitle(QtGui.QApplication.translate( + "plot_series", + "Configure series", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "isLabel").setText( + QtGui.QApplication.translate( + "plot_series", + "No label", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QPushButton, "remove").setText( + QtGui.QApplication.translate( + "plot_series", + "Remove serie", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "styleLabel").setText( + QtGui.QApplication.translate( + "plot_series", + "Line style", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLabel, "markerLabel").setText( + QtGui.QApplication.translate( + "plot_series", + "Marker", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QListWidget, "items").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "List of available series", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QLineEdit, "label").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "Line title", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "isLabel").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "If checked serie will not be considered for legend", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QComboBox, "lineStyle").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "Line style", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QComboBox, "markers").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "Marker style", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QDoubleSpinBox, "lineWidth").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "Line width", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QSpinBox, "markerSize").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "Marker size", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QPushButton, "color").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "Line and marker color", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QPushButton, "remove").setToolTip( + QtGui.QApplication.translate( + "plot_series", + "Removes this serie", + None, + QtGui.QApplication.UnicodeUTF8)) + + def fillStyles(self): + """Fill the style combo boxes with the availabel ones.""" + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.style = self.widget(QtGui.QComboBox, "lineStyle") + form.marker = self.widget(QtGui.QComboBox, "markers") + # Line styles + linestyles = Line2D.lineStyles.keys() + for i in range(0, len(linestyles)): + style = linestyles[i] + string = "\'" + str(style) + "\'" + string += " (" + Line2D.lineStyles[style] + ")" + form.style.addItem(string) + # Markers + markers = Line2D.markers.keys() + for i in range(0, len(markers)): + marker = markers[i] + string = "\'" + str(marker) + "\'" + string += " (" + Line2D.markers[marker] + ")" + form.marker.addItem(string) + + def onItem(self, row): + """Executed when the selected item is modified.""" + if not self.skip: + self.skip = True + + self.item = row + + self.updateUI() + self.skip = False + + def onData(self): + """Executed when the selected item data is modified.""" + if not self.skip: + self.skip = True + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.label = self.widget(QtGui.QLineEdit, "label") + form.isLabel = self.widget(QtGui.QCheckBox, "isLabel") + form.style = self.widget(QtGui.QComboBox, "lineStyle") + form.marker = self.widget(QtGui.QComboBox, "markers") + form.width = self.widget(QtGui.QDoubleSpinBox, "lineWidth") + form.size = self.widget(QtGui.QSpinBox, "markerSize") + # Ensure that selected serie exist + if self.item >= len(Plot.series()): + self.updateUI() + return + # Set label + serie = Plot.series()[self.item] + if(form.isLabel.isChecked()): + serie.name = None + form.label.setEnabled(False) + else: + serie.name = form.label.text() + form.label.setEnabled(True) + # Set line style and marker + style = form.style.currentIndex() + linestyles = Line2D.lineStyles.keys() + serie.line.set_linestyle(linestyles[style]) + marker = form.marker.currentIndex() + markers = Line2D.markers.keys() + serie.line.set_marker(markers[marker]) + # Set line width and marker size + serie.line.set_linewidth(form.width.value()) + serie.line.set_markersize(form.size.value()) + plt.update() + # Regenerate series labels + self.setList() + self.skip = False + + def onColor(self): + """ Executed when color pallete is requested. """ + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.color = self.widget(QtGui.QPushButton, "color") + + # Ensure that selected serie exist + if self.item >= len(Plot.series()): + self.updateUI() + return + # Show widget to select color + col = QtGui.QColorDialog.getColor() + # Send color to widget and serie + if col.isValid(): + serie = plt.series[self.item] + form.color.setStyleSheet( + "background-color: rgb({}, {}, {});".format(col.red(), + col.green(), + col.blue())) + serie.line.set_color((col.redF(), col.greenF(), col.blueF())) + plt.update() + + def onRemove(self): + """Executed when the data serie must be removed.""" + plt = Plot.getPlot() + if not plt: + self.updateUI() + return + # Ensure that selected serie exist + if self.item >= len(Plot.series()): + self.updateUI() + return + # Remove serie + Plot.removeSerie(self.item) + self.setList() + self.updateUI() + plt.update() + + def onMdiArea(self, subWin): + """Executed when a new window is selected on the mdi area. + + Keyword arguments: + subWin -- Selected window. + """ + plt = Plot.getPlot() + if plt != subWin: + self.updateUI() + + def updateUI(self): + """ Setup UI controls values if possible """ + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.items = self.widget(QtGui.QListWidget, "items") + form.label = self.widget(QtGui.QLineEdit, "label") + form.isLabel = self.widget(QtGui.QCheckBox, "isLabel") + form.style = self.widget(QtGui.QComboBox, "lineStyle") + form.marker = self.widget(QtGui.QComboBox, "markers") + form.width = self.widget(QtGui.QDoubleSpinBox, "lineWidth") + form.size = self.widget(QtGui.QSpinBox, "markerSize") + form.color = self.widget(QtGui.QPushButton, "color") + form.remove = self.widget(QtGui.QPushButton, "remove") + plt = Plot.getPlot() + form.items.setEnabled(bool(plt)) + form.label.setEnabled(bool(plt)) + form.isLabel.setEnabled(bool(plt)) + form.style.setEnabled(bool(plt)) + form.marker.setEnabled(bool(plt)) + form.width.setEnabled(bool(plt)) + form.size.setEnabled(bool(plt)) + form.color.setEnabled(bool(plt)) + form.remove.setEnabled(bool(plt)) + if not plt: + self.plt = plt + form.items.clear() + return + self.skip = True + # Refill list + if self.plt != plt or len(Plot.series()) != form.items.count(): + self.plt = plt + self.setList() + # Ensure that have series + if not len(Plot.series()): + form.label.setEnabled(False) + form.isLabel.setEnabled(False) + form.style.setEnabled(False) + form.marker.setEnabled(False) + form.width.setEnabled(False) + form.size.setEnabled(False) + form.color.setEnabled(False) + form.remove.setEnabled(False) + return + # Set label + serie = Plot.series()[self.item] + if serie.name is None: + form.isLabel.setChecked(True) + form.label.setEnabled(False) + form.label.setText("") + else: + form.isLabel.setChecked(False) + form.label.setText(serie.name) + # Set line style and marker + form.style.setCurrentIndex(0) + linestyles = Line2D.lineStyles.keys() + for i in range(0, len(linestyles)): + style = linestyles[i] + if style == serie.line.get_linestyle(): + form.style.setCurrentIndex(i) + form.marker.setCurrentIndex(0) + markers = Line2D.markers.keys() + for i in range(0, len(markers)): + marker = markers[i] + if marker == serie.line.get_marker(): + form.marker.setCurrentIndex(i) + # Set line width and marker size + form.width.setValue(serie.line.get_linewidth()) + form.size.setValue(serie.line.get_markersize()) + # Set color + color = Colors.colorConverter.to_rgb(serie.line.get_color()) + form.color.setStyleSheet("background-color: rgb({}, {}, {});".format( + int(color[0] * 255), + int(color[1] * 255), + int(color[2] * 255))) + self.skip = False + + def setList(self): + """Setup the UI control values if it is possible.""" + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.items = self.widget(QtGui.QListWidget, "items") + form.items.clear() + series = Plot.series() + for i in range(0, len(series)): + serie = series[i] + string = 'serie ' + str(i) + ': ' + if serie.name is None: + string = string + '\"No label\"' + else: + string = string + serie.name + form.items.addItem(string) + # Ensure that selected item is correct + if len(series) and self.item >= len(series): + self.item = len(series) - 1 + form.items.setCurrentIndex(self.item) + def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Plot/plotSeries/__init__.py b/src/Mod/Plot/plotSeries/__init__.py index 24058d7a93ee..6a97f58b26af 100644 --- a/src/Mod/Plot/plotSeries/__init__.py +++ b/src/Mod/Plot/plotSeries/__init__.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,16 +21,9 @@ #* * #*************************************************************************** -# FreeCAD modules -import FreeCAD -import FreeCADGui - -# Qt libraries -from PyQt4 import QtGui,QtCore - -# Main object import TaskPanel + def load(): - """ Loads the tool """ - TaskPanel.createTask() + """Load the tool""" + TaskPanel.createTask() diff --git a/src/Mod/Plot/plotUtils/Paths.py b/src/Mod/Plot/plotUtils/Paths.py index b03f3f64aafd..800ed4c5a6f9 100644 --- a/src/Mod/Plot/plotUtils/Paths.py +++ b/src/Mod/Plot/plotUtils/Paths.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -21,11 +21,13 @@ #* * #*************************************************************************** -import FreeCAD, FreeCADGui, os +import FreeCAD +import FreeCADGui +import os + def modulePath(): - """returns the current Plot module path - @return Module path""" + """returns the current Plot module path.""" path1 = FreeCAD.ConfigGet("AppHomePath") + "Mod/Plot" path2 = FreeCAD.ConfigGet("UserAppData") + "Mod/Plot" if os.path.exists(path2): @@ -33,29 +35,14 @@ def modulePath(): else: return path1 + def iconsPath(): - """returns the current Plot module icons path - @return Icons path""" + """returns the current Plot module icons path.""" path = modulePath() + "/resources/icons" return path + def translationsPath(): - """returns the current Plot module translations path - @return Icons path""" + """returns the current Plot module translations path.""" path = modulePath() + "/resources/translations" return path - -def getPathFromFile(fileName): - """ Gets the directory path from a file name - @param fileName Name of the file - @return Directory path. - """ - if not fileName: - return '' - i = 1 - try: - while 1: - i = fileName.index("/", i+1) - except ValueError: - pass - return fileName[0:i+1] diff --git a/src/Mod/Plot/plotUtils/__init__.py b/src/Mod/Plot/plotUtils/__init__.py index 00b200f140cf..70392f2ea174 100644 --- a/src/Mod/Plot/plotUtils/__init__.py +++ b/src/Mod/Plot/plotUtils/__init__.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -20,6 +20,3 @@ #* USA * #* * #*************************************************************************** - -# Empty file to treat the folder as a package -