diff --git a/bazaar/Controls4U/Controls4U.cpp b/bazaar/Controls4U/Controls4U.cpp index ee5569bd5..2f0b8ce21 100644 --- a/bazaar/Controls4U/Controls4U.cpp +++ b/bazaar/Controls4U/Controls4U.cpp @@ -210,7 +210,7 @@ bool SetFirstChild(Ctrl *ctrl) { // } //} } - Ctrl::Layout(); + //Ctrl::Layout(); } void StaticImage::Paint(Draw& w) { diff --git a/bazaar/Controls4U/Controls4U.upp b/bazaar/Controls4U/Controls4U.upp index 93b114566..bc23ca49a 100644 --- a/bazaar/Controls4U/Controls4U.upp +++ b/bazaar/Controls4U/Controls4U.upp @@ -11,8 +11,6 @@ file Controls4U.h, DrawingCanvas.cpp, DrawingCanvas.h, - ImgCtrl.cpp, - ImgCtrl.h, Controls4U.usc, Controls4U.lay, Controls4U.iml, diff --git a/bazaar/Controls4U/Controls4U.usc b/bazaar/Controls4U/Controls4U.usc index 92a3bca8a..eeed85c10 100644 --- a/bazaar/Controls4U/Controls4U.usc +++ b/bazaar/Controls4U/Controls4U.usc @@ -1,8 +1,5 @@ // Some basic functions to begin -fn Pi() { - return 3.14159265; -} fn atan_base(z) { return z - z*z*z/3 + z*z*z*z*z/5 - z*z*z*z*z*z*z/7 + z*z*z*z*z*z*z*z*z/9 - z*z*z*z*z*z*z*z*z*z*z/11 + z*z*z*z*z*z*z*z*z*z*z*z*z/13; @@ -15,6 +12,9 @@ fn atan(z) { else return 3*Pi()/2 - atan_base(1/z); } +fn Pi() { + return 4*atan(1); +} fn ToRad(angle) { if (angle > 0) return angle*Pi()/180; @@ -33,6 +33,13 @@ fn double(n) { return n; } +fn PaintRect(w, left, top, right, bottom, width, color) +{ + w.DrawLine(left, top, right, top, width, color); + w.DrawLine(right, top, right, bottom, width, color); + w.DrawLine(right, bottom, left, bottom, width, color); + w.DrawLine(left, bottom, left, top, width, color); +} fn PaintEllipse(w, left, top, right, bottom, width, color) { if (width < 1) @@ -1214,3 +1221,44 @@ ctrl Knob { } } +ctrl PainterCanvas { + group "Static"; + + GetMinSize() { return Size(0, 0); } + GetStdSize() { return Size(64, 24); } + + Frame SetFrame @1; + bool SetAlwaysFitInCanvas = true; + bool SetShowWindow = true; + + Paint(w) { + r = GetRect(); + + DrawCtrlFrame(w, r, .SetFrame); + + sz = Size(r.right - r.left, r.bottom - r.top); + + DeflateRect(r); + sz = Size(r.right - r.left, r.bottom - r.top); + w.DrawRect(r.left, r.top, sz.cx, sz.cy, .SetBackground); + img = "Controls4U:Controls4U.iml:ImageSample"; + if (.SetAlwaysFitInCanvas) { + imagesize = GetImageSize(img); + rectaspect = sz.cx/sz.cy; + imageaspect = imagesize.cx/imagesize.cy; + if (rectaspect > imageaspect) + w.DrawImage(r.left+(sz.cx-imageaspect*sz.cy)/2, r.top, imageaspect*sz.cy, sz.cy, img); + else + w.DrawImage(r.left, r.top+(sz.cy-sz.cx/imageaspect)/2, sz.cx, sz.cx/imageaspect, img); + } else { + w.DrawImage(r.left, r.top, img); + } + if (.SetShowWindow) { + twidth = 100; + theight = int(twidth*double(sz.cy)/sz.cx); + tx = sz.cx-twidth-20; + ty = sz.cy-theight-20; + PaintRect(w, tx, ty, tx+twidth, tx+theight, 1, :SBlack); + } + } +} diff --git a/bazaar/Controls4U/DrawingCanvas.cpp b/bazaar/Controls4U/DrawingCanvas.cpp index 3576d878c..04259baa3 100644 --- a/bazaar/Controls4U/DrawingCanvas.cpp +++ b/bazaar/Controls4U/DrawingCanvas.cpp @@ -475,7 +475,7 @@ void DrawingCanvas::Paint(Draw& w) { void DrawingCanvas::DoPaint(Painter& sw) { sw.Translate(translateX, translateY); sw.Rotate(rotate); - sw.Scale(scale, scale); + sw.Scale(scale); sw.Opacity(opacity); sw.LineCap(linecap); sw.LineJoin(linejoin); @@ -558,3 +558,153 @@ void DrawingCanvas::LeftUp(Point p, dword keyflags) { selectionWindow.isSelected = false; } } + +PainterCanvas::PainterCanvas() { + rotate = 0; + /*translateX = translateY = 0; + scale = 1;*/ + + mode = MODE_ANTIALIASED; // MODE_NOAA, MODE_SUBPIXEL + linejoin = LINEJOIN_MITER; + linecap = LINECAP_BUTT; + opacity = 1; + scaleFactor = 1.2; + backColor = Null; + backImage = Null; + colorUnderBackgroundImage = false; + alwaysFitInCanvas = true; + Layout(); + showWindow = true; + + focusMove.focusMoving = false; +} + +void PainterCanvas::Paint(Draw& w) { + Size sz = GetSize(); + ImageBuffer ib(sz); + BufferPainter sw(ib, mode); + + sw.Translate(translateX, translateY); + sw.Rotate(rotate); + sw.Scale(scale); + sw.Opacity(opacity); + sw.LineCap(linecap); + sw.LineJoin(linejoin); + //if (/*IsNull(backImage) || */colorUnderBackgroundImage) + // sw.Clear(backColor); + //else + // sw.Clear(RGBAZero()); + if (backColor) + sw.Clear(backColor); + else + sw.Clear(Gray()); + //else { + // Color c = Null; + // sw.Clear(c); + //} + + if (canvasSize.cx > 0 && canvasSize.cy > 0) { + if (!IsNull(backImage)) + sw.Rectangle(0, 0, canvasSize.cx, canvasSize.cy).Fill(backImage, 0, 0, canvasSize.cx, 0) + .Stroke(0, Black()); + + WhenPaint(sw); + } + w.DrawImage(0, 0, ib); + + if (!showWindow/* || canvasSize.cx <= 0 || canvasSize.cy <= 0*/) + return; + + int twidth = 100; + int theight = int(twidth*double(canvasSize.cy)/canvasSize.cx); + int tx = sz.cx-twidth-20; + int ty = sz.cy-theight-20; + + ImageBuffer tib(twidth, theight); + BufferPainter tsw(tib, mode); + + tsw.Scale(double(twidth)/canvasSize.cx); + + if (IsNull(backImage) || colorUnderBackgroundImage) + tsw.Clear(backColor); + + if (!IsNull(backImage)) + tsw.Rectangle(0, 0, canvasSize.cx, canvasSize.cy).Fill(backImage, 0, 0, canvasSize.cx, 0) + .Stroke(0, Black()); + + if (canvasSize.cx > 0 && canvasSize.cy > 0) + WhenPaint(tsw); + + w.DrawImage(tx, ty, twidth, theight, tib); + DrawRectLine(w, tx-1, ty-1, twidth+1, theight+1, 1, Black()); + + double rateRep = double(twidth)/(canvasSize.cy*scale); + DrawRectLine(w, int(tx-translateX*rateRep-1), int(ty-translateY*rateRep-1), + 1+int(twidth*sz.cx/((canvasSize.cx - translateX*rateRep)*scale)), + 1+int(theight*sz.cy/((canvasSize.cy - translateY*rateRep)*scale)), 1, Black()); +} + +void PainterCanvas::Layout() { + if (alwaysFitInCanvas) + FitInCanvas(); +} + +void PainterCanvas::MouseWheel(Point p, int zdelta, dword keyflags) { + double factor; + if(zdelta > 0) + factor = scaleFactor; + else + factor = 1/scaleFactor; + scale *= factor; + + Size sz = GetSize(); + translateX = sz.cx*(1-factor)/2. + translateX*factor; + translateY = sz.cy*(1-factor)/2. + translateY*factor; + + Refresh(); +} + +void PainterCanvas::FitInCanvas() { + Rect r = FitInFrame(GetSize(), GetCanvasSize()); + + double scalex = GetSize().cx/double(GetCanvasSize().cx); + double scaley = GetSize().cy/double(GetCanvasSize().cy); + + scale = min(scalex, scaley); + translateX = r.left; + translateY = r.top; + + Refresh(); +} + +void PainterCanvas::MiddleDown(Point p, dword keyflags) { + focusMove.lastFocusPoint = p; + focusMove.focusMoving = true; +} + +void PainterCanvas::MiddleUp(Point p, dword keyflags) { + focusMove.focusMoving = false; +} + +void PainterCanvas::MouseLeave() { + focusMove.focusMoving = false; +} + +void PainterCanvas::MouseMove(Point p, dword keyflags) { + if (focusMove.focusMoving) { + translateX -= focusMove.lastFocusPoint.x - p.x; + translateY -= focusMove.lastFocusPoint.y - p.y; + focusMove.lastFocusPoint = p; + + Refresh(); + } +} + +void PainterCanvas::SetBackground(Image &image) { + backImage = image; + if (backImage.GetSize() != canvasSize) { + SetCanvasSize(backImage.GetSize()); + Layout(); + } +} + diff --git a/bazaar/Controls4U/DrawingCanvas.h b/bazaar/Controls4U/DrawingCanvas.h index 1ba4e39ff..5f19ac4be 100644 --- a/bazaar/Controls4U/DrawingCanvas.h +++ b/bazaar/Controls4U/DrawingCanvas.h @@ -1,497 +1,548 @@ -#ifndef _Controls4U_DrawingCanvas_h_ -#define _Controls4U_DrawingCanvas_h_ - -class Svg2DTransform { -public: - Svg2DTransform() {Init();} - Svg2DTransform(Svg2DTransform &transf) {*this = transf;} - void Init() { - transX = transY = 0; - angle = 0; - scaleX = scaleY = 1; - } - void Apply(Painter &sw) { - sw.End(); - sw.Begin(); - sw.Translate(transX, transY); - sw.Scale(scaleX, scaleY); - sw.Rotate(angle); - } - void Translate(double x, double y) { - transX += x; - transY += y; - } - void Scale(double x, double y) { - scaleX *= x; - scaleY *= y; - } - void Rotate(double ang) { - angle += ang; - } - Svg2DTransform &operator=(const Svg2DTransform &transf) { - if (this == &transf) // Same object? - return *this; - transX = transf.transX; - transY = transf.transY; - angle = transf.angle; - scaleX = transf.scaleX; - scaleY = transf.scaleY; - return *this; - } - Svg2DTransform &operator+=(const Svg2DTransform &transf) { - if (this == &transf) // Same object? - return *this; - transX += transf.transX; - transY += transf.transY; - angle += transf.angle; - scaleX *= transf.scaleX; - scaleY *= transf.scaleY; - return *this; - } - Svg2DTransform &SetTranslate(double x, double y) { - transX = x; - transY = y; - return *this; - } - Svg2DTransform &SetScale(double x, double y) { - scaleX = x; - scaleY = y; - return *this; - } - Svg2DTransform &SetRotate(double a) { - angle = a; - return *this; - } - -private: - double transX; - double transY; - double angle; - double scaleX; - double scaleY; -}; - -class SvgStyle { -public: - SvgStyle() {Init();} - SvgStyle(SvgStyle &transf) {*this = transf;} - void Init() { - strokeWidth = Null; - strokeFill = Null; - strokeColor = Null; - strokeOpacity = Null; - } - void Set(String str); - void Apply(Painter &sw); - SvgStyle &operator=(const SvgStyle &style); - SvgStyle &operator+=(const SvgStyle &style); - - SvgStyle &SetStrokeWidth(int c) {strokeWidth = c; return *this;} - SvgStyle &SetStrokeFill(Color c) {strokeFill = c; return *this;} - SvgStyle &SetStrokeColor(Color c) {strokeColor = c; return *this;} - SvgStyle &SetStrokeOpacity(double c) {strokeOpacity = c; return *this;} - -public: - int strokeWidth; - Color strokeFill; - Color strokeColor; - double strokeOpacity; -}; - -class GraphElemLimits : public Rectf { -public: - GraphElemLimits() { - Reset(); - } - void Reset() { - left = top = -DOUBLE_NULL_LIM; - right = bottom = DOUBLE_NULL_LIM; - } - void UpdateLimits(const Pointf &p) { - UpdateLimitsH(p.x); - UpdateLimitsV(p.y); - } - void UpdateLimitsH(double x) { - if (x > right) - right = x; - if (x < left) - left = x; - } - void UpdateLimitsV(double y) { - if (y > bottom) - bottom = y; - if (y < top) - top = y; - } - void Cubic(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) { - /*DoMove0(); - CubicData& m = PathAdd(CUBIC); - m.p1 = PathPoint(p1, rel); - ccontrol = m.p2 = PathPoint(p2, rel); - m.p = EndPoint(p, rel);*/ - //UpdateLimits(p1); - UpdateLimits(p2); - UpdateLimits(p); - } -}; - -class GraphElem { -public: - Svg2DTransform transf; - SvgStyle style; - GraphElemLimits limits; - - virtual void Paint(Painter &sw, Svg2DTransform transf, SvgStyle style, bool firstLayer) {}; - virtual void SetLimits() {}; - virtual void PaintLimits(Painter &sw) { - if (limits == GraphElemLimits()) - return; - - sw.Rectangle(limits.left, limits.top, limits.GetWidth(), limits.GetHeight()) - .Opacity(0.3).Stroke(0.5, Black()).Fill(LtBlue()); - sw.Move(limits.left, limits.top); - sw.Line(limits.right, limits.bottom).Opacity(0.3).Stroke(0.5, Black()); - sw.Move(limits.right, limits.top); - sw.Line(limits.left, limits.bottom).Opacity(0.3).Stroke(0.5, Black()); - } - virtual ~GraphElem() {}; -}; - - -class LineElem : public GraphElem { -public: - virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { - _transf += transf; - _transf.Apply(sw); - sw.Move(x1, y1); - sw.Line(x2, y2); - _style += style; - _style.Apply(sw); - PaintLimits(sw); - } - virtual void SetLimits() { - limits.left = x1; - limits.top = y1; - limits.right = x2; - limits.bottom = y2; - } - LineElem(double x1, double y1, double x2, double y2) : x1(x1), y1(y1), x2(x2), y2(y2) {SetLimits();} - LineElem() {x1 = x2 = y1 = y2 = 0;} - -//private: - double x1, y1, x2, y2; -}; - -class RectElem : public GraphElem { -public: - virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { - _transf += transf; - _transf.Apply(sw); - sw.Rectangle(x, y, width, height); - _style += style; - _style.Apply(sw); - PaintLimits(sw); - } - virtual void SetLimits() { - limits.left = x; - limits.top = y; - limits.right = x + width; - limits.bottom = y + height; - } - RectElem(double x, double y, double width, double height) : x(x), y(y), width(width), height(height) {SetLimits();} - RectElem() {x = y = width = height = 0;} - -//private: - double x, y, width, height; -}; - -class EllipseElem : public GraphElem { -public: - virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { - _transf += transf; - _transf.Apply(sw); - sw.Ellipse(x, y, width, height); - _style += style; - _style.Apply(sw); - PaintLimits(sw); - } - virtual void SetLimits() { - limits.left = x - width; - limits.top = y - height; - limits.right = x + width; - limits.bottom = y + height; - } - EllipseElem(double x, double y, double width, double height) : x(x), y(y), width(width), height(height) {SetLimits();} - EllipseElem() {x = y = width = height = 0;} - -//private: - double x, y, width, height; -}; - -class ImageElem : public GraphElem { -public: - virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { - if (IsNull(img)) - img = StreamRaster::LoadFileAny(fileName); - _transf += transf; - _transf.Apply(sw); - sw.Rectangle(x, y, width, height).Fill(img, x, y, width, 0).Stroke(0, Black()); - _style += style; - _style.Apply(sw); - PaintLimits(sw); - } - virtual void SetLimits() { - limits.left = x; - limits.top = y; - limits.right = x + width; - limits.bottom = y + height; - } - ImageElem(double x, double y, double width, double height, String fileName) : x(x), y(y), - width(width), height(height), fileName(fileName) {img = Null; SetLimits();} - ImageElem() {x = y = width = height = 0; img = Null;} - -//private: - double x, y, width, height; - String fileName; - Image img; -}; - -class PolygonElem : public GraphElem { -public: - virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { - _transf += transf; - _transf.Apply(sw); - sw.Move(points[0].x, points[0].y); - for (int i = 1; i < points.GetCount(); ++i) - sw.Line(points[i].x, points[i].y); - _style += style; - _style.Apply(sw); - PaintLimits(sw); - } - virtual void SetLimits() { - limits.Reset(); - for (int i = 0; i < points.GetCount(); ++i) - limits.UpdateLimits(points[i]); - } - PolygonElem() {} - -//private: - Array points; -}; - -class TextElem : public GraphElem { -public: - virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { - _transf.Translate(x, y-f.GetHeight()/factor); - _transf.Scale(1./factor, 1./factor); - _transf += transf; - _transf.Apply(sw); - sw.Text(0, 0, text, f); - _style += style; - _style.Apply(sw); - PaintLimits(sw); - } - virtual void SetLimits() { - limits.left = 0; - limits.top = 0; - - FontInfo fi = f.Info(); - limits.right = limits.left; - WString wtext(text); - for (int i = 0; i < wtext.GetCount(); ++i) - limits.right += fi[wtext[i]]; - limits.bottom = limits.top + f.GetHeight(); - } - TextElem() { - factor = 20; - f.Face(Font::ARIAL); - f.Height(12); - } - -//private: - double x, y; - String text; - String font; - Font f; - int factor; -}; - -class PathElem : public GraphElem { -public: - virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { - _transf += transf; - _transf.Apply(sw); - if (!path.IsEmpty()) - sw.Path(path); - _style += style; - _style.Apply(sw); - PaintLimits(sw); - } - bool ReadBool(CParser& p) { // Painter:: - while(p.Char(',')); - if(p.Char('1')) return true; - p.Char('0'); - return false; - } - double ReadDouble(CParser& p) { // Painter:: - while(p.Char(',')); - return p.IsDouble() ? p.ReadDouble() : 0; - } - Pointf ReadPoint(CParser& p) { // Painter:: - Pointf t; - t.x = ReadDouble(p); - t.y = ReadDouble(p); - return t; - } - virtual void SetLimits() { - CParser p(path); - limits.Reset(); - while(!p.IsEof()) { - int c = p.GetChar(); - p.Spaces(); - bool rel = IsLower(c); - Pointf t, t1, t2; - switch(ToUpper(c)) { - case 'M': - t = ReadPoint(p); - //Move(t, rel); - limits.UpdateLimits(t); - case 'L': - while(p.IsDouble()) { - t = ReadPoint(p); - //Line(t, rel); - limits.UpdateLimits(t); - } - break; - case 'Z': - //Close(); - break; - case 'H': - while(p.IsDouble()) - //Line(p.ReadDouble(), Null, rel); - limits.UpdateLimitsH(p.ReadDouble()); - break; - case 'V': - while(p.IsDouble()) - //Line(Null, p.ReadDouble(), rel); - limits.UpdateLimitsV(p.ReadDouble()); - ; - break; - case 'C': - while(p.IsDouble()) { - t1 = ReadPoint(p); - t2 = ReadPoint(p); - t = ReadPoint(p); - limits.Cubic(t1, t2, t, rel); - //Cubic(t1, t2, t, rel); - } - break; - case 'S': - while(p.IsDouble()) { - t2 = ReadPoint(p); - t = ReadPoint(p); - //Cubic(t2, t, rel); - //limits.UpdateLimits(t2); - limits.UpdateLimits(t); - } - break; - case 'Q': - while(p.IsDouble()) { - t1 = ReadPoint(p); - t = ReadPoint(p); - //Quadratic(t1, t, rel); - //limits.UpdateLimits(t1); - limits.UpdateLimits(t); - } - break; - case 'T': - while(p.IsDouble()) { - t = ReadPoint(p); - //Quadratic(t, rel); - limits.UpdateLimits(t); - } - break; - case 'A': - while(p.IsDouble()) { - t1 = ReadPoint(p); - /* double xangle = */ ReadDouble(p); - /* bool large = */ ReadBool(p); - /* bool sweep = */ ReadBool(p); - t = ReadPoint(p); - //SvgArc(t1, xangle * M_PI / 180.0, large, sweep, t, rel); - } - break; - default: - return; - } - } - } - PathElem() {} - -//private: - String path; -}; - - -class GraphElemList : public GraphElem { -public: - Array elems; - - String title; - - void Paint(Painter &sw, Svg2DTransform transf, SvgStyle style, bool firstLayer = false); - void Clear(); -}; - - -class CanvasSelector { -typedef CanvasSelector CLASSNAME; -public: - -}; - -class DrawingCanvas : public Ctrl { -typedef DrawingCanvas CLASSNAME; -public: - DrawingCanvas(); - - GraphElemList elemList; - -protected: - virtual void Paint(Draw& draw); - -private: - double translateX, translateY; - double rotate; - double scale; - bool transparent; - double opacity; - int linejoin, linecap; - int quality; - double scaleFactor; - - void DoPaint(Painter& sw); - - virtual void MouseMove(Point p, dword keyflags); - virtual void MouseWheel(Point p, int zdelta, dword keyflags); - virtual void MiddleDown(Point p, dword keyflags); - virtual void MiddleUp(Point p, dword keyflags); - virtual void MouseLeave(); - struct FocusMove { - bool focusMoving; - Point lastFocusPoint; - } focusMove; - - virtual void LeftDown(Point p, dword keyflags); - virtual void LeftUp(Point p, dword keyflags); - struct SelectionWindow { - bool isSelected; - Rect selected; - } selectionWindow; -}; - -bool LoadSvg(DrawingCanvas &canvas, String fileName); - - -#endif - +#ifndef _Controls4U_DrawingCanvas_h_ +#define _Controls4U_DrawingCanvas_h_ + +class Svg2DTransform { +public: + Svg2DTransform() {Init();} + Svg2DTransform(Svg2DTransform &transf) {*this = transf;} + void Init() { + transX = transY = 0; + angle = 0; + scaleX = scaleY = 1; + } + void Apply(Painter &sw) { + sw.End(); + sw.Begin(); + sw.Translate(transX, transY); + sw.Scale(scaleX, scaleY); + sw.Rotate(angle); + } + void Translate(double x, double y) { + transX += x; + transY += y; + } + void Scale(double x, double y) { + scaleX *= x; + scaleY *= y; + } + void Rotate(double ang) { + angle += ang; + } + Svg2DTransform &operator=(const Svg2DTransform &transf) { + if (this == &transf) // Same object? + return *this; + transX = transf.transX; + transY = transf.transY; + angle = transf.angle; + scaleX = transf.scaleX; + scaleY = transf.scaleY; + return *this; + } + Svg2DTransform &operator+=(const Svg2DTransform &transf) { + if (this == &transf) // Same object? + return *this; + transX += transf.transX; + transY += transf.transY; + angle += transf.angle; + scaleX *= transf.scaleX; + scaleY *= transf.scaleY; + return *this; + } + Svg2DTransform &SetTranslate(double x, double y) { + transX = x; + transY = y; + return *this; + } + Svg2DTransform &SetScale(double x, double y) { + scaleX = x; + scaleY = y; + return *this; + } + Svg2DTransform &SetRotate(double a) { + angle = a; + return *this; + } + +private: + double transX; + double transY; + double angle; + double scaleX; + double scaleY; +}; + +class SvgStyle { +public: + SvgStyle() {Init();} + SvgStyle(SvgStyle &transf) {*this = transf;} + void Init() { + strokeWidth = Null; + strokeFill = Null; + strokeColor = Null; + strokeOpacity = Null; + } + void Set(String str); + void Apply(Painter &sw); + SvgStyle &operator=(const SvgStyle &style); + SvgStyle &operator+=(const SvgStyle &style); + + SvgStyle &SetStrokeWidth(int c) {strokeWidth = c; return *this;} + SvgStyle &SetStrokeFill(Color c) {strokeFill = c; return *this;} + SvgStyle &SetStrokeColor(Color c) {strokeColor = c; return *this;} + SvgStyle &SetStrokeOpacity(double c) {strokeOpacity = c; return *this;} + +public: + int strokeWidth; + Color strokeFill; + Color strokeColor; + double strokeOpacity; +}; + +class GraphElemLimits : public Rectf { +public: + GraphElemLimits() { + Reset(); + } + void Reset() { + left = top = -DOUBLE_NULL_LIM; + right = bottom = DOUBLE_NULL_LIM; + } + void UpdateLimits(const Pointf &p) { + UpdateLimitsH(p.x); + UpdateLimitsV(p.y); + } + void UpdateLimitsH(double x) { + if (x > right) + right = x; + if (x < left) + left = x; + } + void UpdateLimitsV(double y) { + if (y > bottom) + bottom = y; + if (y < top) + top = y; + } + void Cubic(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) { + /*DoMove0(); + CubicData& m = PathAdd(CUBIC); + m.p1 = PathPoint(p1, rel); + ccontrol = m.p2 = PathPoint(p2, rel); + m.p = EndPoint(p, rel);*/ + //UpdateLimits(p1); + UpdateLimits(p2); + UpdateLimits(p); + } +}; + +class GraphElem { +public: + Svg2DTransform transf; + SvgStyle style; + GraphElemLimits limits; + + virtual void Paint(Painter &sw, Svg2DTransform transf, SvgStyle style, bool firstLayer) {}; + virtual void SetLimits() {}; + virtual void PaintLimits(Painter &sw) { + if (limits == GraphElemLimits()) + return; + + sw.Rectangle(limits.left, limits.top, limits.GetWidth(), limits.GetHeight()) + .Opacity(0.3).Stroke(0.5, Black()).Fill(LtBlue()); + sw.Move(limits.left, limits.top); + sw.Line(limits.right, limits.bottom).Opacity(0.3).Stroke(0.5, Black()); + sw.Move(limits.right, limits.top); + sw.Line(limits.left, limits.bottom).Opacity(0.3).Stroke(0.5, Black()); + } + virtual ~GraphElem() {}; +}; + + +class LineElem : public GraphElem { +public: + virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { + _transf += transf; + _transf.Apply(sw); + sw.Move(x1, y1); + sw.Line(x2, y2); + _style += style; + _style.Apply(sw); + PaintLimits(sw); + } + virtual void SetLimits() { + limits.left = x1; + limits.top = y1; + limits.right = x2; + limits.bottom = y2; + } + LineElem(double x1, double y1, double x2, double y2) : x1(x1), x2(x2), y1(y1), y2(y2) {SetLimits();} + LineElem() {x1 = x2 = y1 = y2 = 0;} + +//private: + double x1, y1, x2, y2; +}; + +class RectElem : public GraphElem { +public: + virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { + _transf += transf; + _transf.Apply(sw); + sw.Rectangle(x, y, width, height); + _style += style; + _style.Apply(sw); + PaintLimits(sw); + } + virtual void SetLimits() { + limits.left = x; + limits.top = y; + limits.right = x + width; + limits.bottom = y + height; + } + RectElem(double x, double y, double width, double height) : x(x), y(y), width(width), height(height) {SetLimits();} + RectElem() {x = y = width = height = 0;} + +//private: + double x, y, width, height; +}; + +class EllipseElem : public GraphElem { +public: + virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { + _transf += transf; + _transf.Apply(sw); + sw.Ellipse(x, y, width, height); + _style += style; + _style.Apply(sw); + PaintLimits(sw); + } + virtual void SetLimits() { + limits.left = x - width; + limits.top = y - height; + limits.right = x + width; + limits.bottom = y + height; + } + EllipseElem(double x, double y, double width, double height) : x(x), y(y), width(width), height(height) {SetLimits();} + EllipseElem() {x = y = width = height = 0;} + +//private: + double x, y, width, height; +}; + +class ImageElem : public GraphElem { +public: + virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { + if (IsNull(img)) + img = StreamRaster::LoadFileAny(fileName); + _transf += transf; + _transf.Apply(sw); + sw.Rectangle(x, y, width, height).Fill(img, x, y, width, 0).Stroke(0, Black()); + _style += style; + _style.Apply(sw); + PaintLimits(sw); + } + virtual void SetLimits() { + limits.left = x; + limits.top = y; + limits.right = x + width; + limits.bottom = y + height; + } + ImageElem(double x, double y, double width, double height, String fileName) : x(x), y(y), + width(width), height(height), fileName(fileName) {img = Null; SetLimits();} + ImageElem() {x = y = width = height = 0; img = Null;} + +//private: + double x, y, width, height; + String fileName; + Image img; +}; + +class PolygonElem : public GraphElem { +public: + virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { + _transf += transf; + _transf.Apply(sw); + sw.Move(points[0].x, points[0].y); + for (int i = 1; i < points.GetCount(); ++i) + sw.Line(points[i].x, points[i].y); + _style += style; + _style.Apply(sw); + PaintLimits(sw); + } + virtual void SetLimits() { + limits.Reset(); + for (int i = 0; i < points.GetCount(); ++i) + limits.UpdateLimits(points[i]); + } + PolygonElem() {} + +//private: + Array points; +}; + +class TextElem : public GraphElem { +public: + virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { + _transf.Translate(x, y-f.GetHeight()/factor); + _transf.Scale(1./factor, 1./factor); + _transf += transf; + _transf.Apply(sw); + sw.Text(0, 0, text, f); + _style += style; + _style.Apply(sw); + PaintLimits(sw); + } + virtual void SetLimits() { + limits.left = 0; + limits.top = 0; + + FontInfo fi = f.Info(); + limits.right = limits.left; + WString wtext(text); + for (int i = 0; i < wtext.GetCount(); ++i) + limits.right += fi[wtext[i]]; + limits.bottom = limits.top + f.GetHeight(); + } + TextElem() { + factor = 20; + f.Face(Font::ARIAL); + f.Height(12); + } + +//private: + double x, y; + String text; + String font; + Font f; + int factor; +}; + +class PathElem : public GraphElem { +public: + virtual void Paint(Painter &sw, Svg2DTransform _transf, SvgStyle _style, bool) { + _transf += transf; + _transf.Apply(sw); + if (!path.IsEmpty()) + sw.Path(path); + _style += style; + _style.Apply(sw); + PaintLimits(sw); + } + bool ReadBool(CParser& p) { // Painter:: + while(p.Char(',')); + if(p.Char('1')) return true; + p.Char('0'); + return false; + } + double ReadDouble(CParser& p) { // Painter:: + while(p.Char(',')); + return p.IsDouble() ? p.ReadDouble() : 0; + } + Pointf ReadPoint(CParser& p) { // Painter:: + Pointf t; + t.x = ReadDouble(p); + t.y = ReadDouble(p); + return t; + } + virtual void SetLimits() { + CParser p(path); + limits.Reset(); + while(!p.IsEof()) { + int c = p.GetChar(); + p.Spaces(); + bool rel = IsLower(c); + Pointf t, t1, t2; + switch(ToUpper(c)) { + case 'M': + t = ReadPoint(p); + //Move(t, rel); + limits.UpdateLimits(t); + case 'L': + while(p.IsDouble()) { + t = ReadPoint(p); + //Line(t, rel); + limits.UpdateLimits(t); + } + break; + case 'Z': + //Close(); + break; + case 'H': + while(p.IsDouble()) + //Line(p.ReadDouble(), Null, rel); + limits.UpdateLimitsH(p.ReadDouble()); + break; + case 'V': + while(p.IsDouble()) + //Line(Null, p.ReadDouble(), rel); + limits.UpdateLimitsV(p.ReadDouble()); + ; + break; + case 'C': + while(p.IsDouble()) { + t1 = ReadPoint(p); + t2 = ReadPoint(p); + t = ReadPoint(p); + limits.Cubic(t1, t2, t, rel); + //Cubic(t1, t2, t, rel); + } + break; + case 'S': + while(p.IsDouble()) { + t2 = ReadPoint(p); + t = ReadPoint(p); + //Cubic(t2, t, rel); + //limits.UpdateLimits(t2); + limits.UpdateLimits(t); + } + break; + case 'Q': + while(p.IsDouble()) { + t1 = ReadPoint(p); + t = ReadPoint(p); + //Quadratic(t1, t, rel); + //limits.UpdateLimits(t1); + limits.UpdateLimits(t); + } + break; + case 'T': + while(p.IsDouble()) { + t = ReadPoint(p); + //Quadratic(t, rel); + limits.UpdateLimits(t); + } + break; + case 'A': + while(p.IsDouble()) { + t1 = ReadPoint(p); + double xangle = ReadDouble(p); + bool large = ReadBool(p); + bool sweep = ReadBool(p); + t = ReadPoint(p); + //SvgArc(t1, xangle * M_PI / 180.0, large, sweep, t, rel); + } + break; + default: + return; + } + } + } + PathElem() {} + +//private: + String path; +}; + + +class GraphElemList : public GraphElem { +public: + Array elems; + + String title; + + void Paint(Painter &sw, Svg2DTransform transf, SvgStyle style, bool firstLayer = false); + void Clear(); +}; + + +class CanvasSelector { +typedef CanvasSelector CLASSNAME; +public: + +}; + +class DrawingCanvas : public Ctrl { +typedef DrawingCanvas CLASSNAME; +public: + DrawingCanvas(); + + GraphElemList elemList; + +protected: + virtual void Paint(Draw& draw); + +private: + double translateX, translateY; + double rotate; + double scale; + bool transparent; + double opacity; + int linejoin, linecap; + int quality; + double scaleFactor; + + void DoPaint(Painter& sw); + + virtual void MouseMove(Point p, dword keyflags); + virtual void MouseWheel(Point p, int zdelta, dword keyflags); + virtual void MiddleDown(Point p, dword keyflags); + virtual void MiddleUp(Point p, dword keyflags); + virtual void MouseLeave(); + struct FocusMove { + bool focusMoving; + Point lastFocusPoint; + } focusMove; + + virtual void LeftDown(Point p, dword keyflags); + virtual void LeftUp(Point p, dword keyflags); + struct SelectionWindow { + bool isSelected; + Rect selected; + } selectionWindow; +}; + +bool LoadSvg(DrawingCanvas &canvas, String fileName); + + + + +class PainterCanvas : public Ctrl { +typedef PainterCanvas CLASSNAME; +public: + PainterCanvas(); + void SetCanvasSize(Size sz) {canvasSize = sz;}; + Size GetCanvasSize() const {return canvasSize;}; + void SetBackground(Image &image); + Image GetBackground() {return backImage;} + void FitInCanvas(); + + PainterCanvas &SetBackground(Color &color) {backColor = color; Refresh(); return *this;}; + PainterCanvas &SetColorUnderBackgroundImage(bool set) {colorUnderBackgroundImage = set; return *this;}; + PainterCanvas &SetScale(double factor) {scale *= factor; Refresh(); return *this;}; + PainterCanvas &SetAlwaysFitInCanvas(bool fit = true){alwaysFitInCanvas = fit; Refresh(); return *this;} + PainterCanvas &SetMode(int md = MODE_ANTIALIASED) {mode = md; return *this;} + PainterCanvas &SetShowWindow(bool sw = true) {showWindow = sw; return *this;}; + + Callback1 WhenPaint; + +protected: + virtual void Paint(Draw& draw); + virtual void Layout(); + +private: + double translateX, translateY; + double rotate; + double scale; + double opacity; + int linejoin, linecap; + int mode; + double scaleFactor; + Image backImage; + Color backColor; + Size canvasSize; + bool colorUnderBackgroundImage; + bool alwaysFitInCanvas; + bool showWindow; + + virtual void MouseMove(Point p, dword keyflags); + virtual void MouseWheel(Point p, int zdelta, dword keyflags); + virtual void MiddleDown(Point p, dword keyflags); + virtual void MiddleUp(Point p, dword keyflags); + virtual void MouseLeave(); + struct FocusMove { + bool focusMoving; + Point lastFocusPoint; + } focusMove; +}; + +#endif + diff --git a/bazaar/Controls4U/ImgCtrl.cpp b/bazaar/Controls4U/ImgCtrl.cpp deleted file mode 100644 index d6627a2e2..000000000 --- a/bazaar/Controls4U/ImgCtrl.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#include - -using namespace Upp; - -#include "ImgCtrl.h" -#include "Functions4U/Functions4U.h" - -ImgCtrl::ImgCtrl() -{ - BackPaint(); - - x0 = y0 = xDelta = yDelta = 0.; - - moving = false; - lastPoint = Point(0,0); - - factor = 0.0; - width = height = 0; - - showZoom = true; - thumb = true; -} - -bool ImgCtrl::IsEmpty() -{ - return width == 0; -} - -void ImgCtrl::Paint(Draw& w) -{ - WString strTemp; - Size sz = GetSize(); - - w.DrawRect(GetSize(), White); - if(imageRep) { - w.DrawImage((int)x0, (int)y0, imageRep); - if(showZoom) { - strTemp = Format(t_("Zoom: %2.2f"), factor).ToWString(); - w.DrawText(sz.cx-120, sz.cy-13, strTemp, Arial(10)); - } - } - if (thumb && width > 0) { - double rate = 100./width; - int twidth = 100; - int theight = int(rate*height); - int tx = sz.cx-twidth-20; - int ty = sz.cy-theight-20; - - Color black = Black(); - DrawRectLine(w, tx-1, ty-1, twidth+1, theight+1, 1, black); // Borde de la imagen principal - w.DrawImage(tx, ty, twidth, theight, image); - double rateRep = 100./imageRep.GetWidth(); - DrawRectLine(w, int(tx-x0*rateRep-1), int(ty-y0*rateRep-1), - 1+int(twidth*sz.cx/imageRep.GetWidth()), - 1+int(theight*sz.cy/imageRep.GetHeight()), 1, black); // Rectangulo con la parte visible de la imagen - } -} - -Size ZoomProportional(Size frame, Size space, double &x0, double &y0, double scale, double step) { - if (scale == 0) - return Null; - - int frameWidth = frame.cx; - int frameHeight = frame.cy; - - Size ret((int)(scale*space.cx), (int)(scale*space.cy)); - - scale = step; - x0 = frameWidth*(1-scale)/2 + x0*scale; - y0 = frameHeight*(1-scale)/2 + y0*scale; - - return ret; -} - -void ImgCtrl::Zoom(double m_fStep) -{ - if(factor*m_fStep > MAX_ZOOM_FACTOR || factor*m_fStep < MIN_ZOOM_FACTOR) - return; - - factor = factor*m_fStep; - Size s = ZoomProportional(GetSize(), image.GetSize(), x0, y0, factor, m_fStep); - - xDelta = x0; - yDelta = y0; - imageRep = Rescale(image, s, Rect(0, 0, width, height)); - - Refresh(); -} - -/* -Rectf ZoomProportional(Size frame, Rectf &image, double step) { -// if (scale == 0) -// return Null; - - int frameWidth = frame.cx; - int frameHeight = frame.cy; - - Rectf ret; - ret.left = frameWidth*(1-step)/2 + image.left*step; - ret.top = frameHeight*(1-step)/2 + image.top*step; - ret.right = ret.left + step*image.GetWidth(); - ret.bottom = ret.top + step*image.GetHeight(); - - return ret; -} - -void ImgCtrl::Zoom(double m_fStep) -{ - if(m_fFactor*m_fStep > MAX_ZOOM_FACTOR || m_fFactor*m_fStep < MIN_ZOOM_FACTOR) - return; - - Rectf r = Rectf(x0, m_p0y, m_fFactor*m_Img.GetWidth(), m_fFactor*m_Img.GetHeight()); - Rectf rr = ZoomProportional(GetSize(), r, m_fStep); - m_fFactor = m_fFactor*m_fStep; - - m_pUx = x0 = rr.left; - m_pUy = m_p0y = rr.top; - m_ImgRep = Rescale(m_Img, Size(rr.GetWidth(), rr.GetHeight()), Rect(0, 0, Width, Height)); - - Refresh(); -} -*/ -// Resize and center to fit in the control -void ImgCtrl::Fit() -{ - if (image) { - Size szImage = image.GetSize(); - - Rect r = FitInFrame(GetSize(), szImage); - - factor = r.GetWidth()/(double)szImage.cx; - - xDelta = x0 = r.left; - yDelta = y0 = r.top; - imageRep = Rescale(image, Size(r.Width(), r.Height()), Rect(0, 0, szImage.cx, szImage.cy)); - } - Refresh(); -} -// Resize to real img size -void ImgCtrl::RealSize() -{ - if(image) { - xDelta = x0 = 0.; - yDelta = y0 = 0.; - factor = 1.0; - imageRep = image; - - Refresh(); - } -} -void ImgCtrl::GetRectRep(double &left, double &top, double &_width, double &_height) -{ - left = x0; - top = y0; - _width = imageRep.GetWidth(); - _height = imageRep.GetHeight(); -} -void ImgCtrl::GetRepXY(double x, double y, int &repx, int &repy) -{ - repx = int(x*imageRep.GetWidth()/GetWidth() + x0); - repy = int(y*imageRep.GetHeight()/GetHeight() + y0); -} -void ImgCtrl::GetXYRep(int repx, int repy, double &x, double &y) -{ - x = double((repx - xDelta)*GetWidth() - x0)/imageRep.GetWidth(); - y = double((repy - yDelta)*GetHeight() - y0)/imageRep.GetHeight(); -} -void ImgCtrl::MouseWheel(Point p, int zdelta, dword keyflags) -{ - if(zdelta > 0) - Zoom(1.2); - else - Zoom(1/1.2); -} -void ImgCtrl::LocalMenu(Bar& bar) -{ - if(imageRep) { - bar.Add("Window size", THISBACK(Fit)); - bar.Add("Real size", THISBACK(RealSize)); - bar.Add("B&N", THISBACK(BW)); - } -} -void ImgCtrl::RightDown(Point p, dword keyflags) -{ - MenuBar::Execute(THISBACK(LocalMenu)); -} -void ImgCtrl::LeftDown(Point p, dword keyflags) -{ - lastPoint = p; - moving = true; -} -void ImgCtrl::LeftUp(Point p, dword keyflags) -{ - xDelta = x0; //Largou-se o rapo, guardar deslocamento onde parou - yDelta = y0; - moving = false; -} -void ImgCtrl::MouseMove(Point p, dword keyflags) -{ - Point pDif; - - if(moving) { - pDif = lastPoint - p; - - //Exclamation(Format("Last(%d,%d) Actual(%d,%d), Dif(%d,%d)",m_pLastPoint.x,m_pLastPoint.y,p.x,p.y,pDif.x,pDif.y)); - int deslocX = -pDif.x; - int deslocY = -pDif.y; - - x0 = xDelta + deslocX; - y0 = yDelta + deslocY; - - Refresh(); - } -} -void ImgCtrl::Load(const WString fileName) -{ - image.Clear(); - - image = StreamRaster::LoadFileAny(fileName.ToString()); - if(image) - SetImage(image); -} - -bool ImgCtrl::Save(String fileName, String ext, int qualityBpp) -{ - return SaveImage(image, qualityBpp, fileName, ext); -}; - -void ImgCtrl::Print(int n_draw_origin_x, int n_draw_origin_y, int n_image_cx, int n_image_cy) -{ - PrintImage(image, n_draw_origin_x, n_draw_origin_y, n_image_cx, n_image_cy); -} - -void ImgCtrl::SetImage(ImageBuffer img) { - image = img; - width = image.GetWidth(); - height = image.GetHeight(); - Fit(); -}; - -void ImgCtrl::SetImage(Image img) { - image = img; - width = image.GetWidth(); - height = image.GetHeight(); - Fit(); -}; - -void ImgCtrl::SetImage(const char *fileName) { - SetImage(StreamRaster::LoadFileAny(fileName)); -} - -void ImgCtrl::SetZoomVisible(const bool b_show) -{ - showZoom = b_show; -} -void ImgCtrl::SetThumbVisible(bool _thumb) -{ - thumb = _thumb;; -} - -void ImgCtrl::BW() -{ - image = Grayscale(image); - Zoom(1); -} diff --git a/bazaar/Controls4U/ImgCtrl.h b/bazaar/Controls4U/ImgCtrl.h deleted file mode 100644 index 7b85a9be4..000000000 --- a/bazaar/Controls4U/ImgCtrl.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef _Controls4U_ImgCtrl_h_ -#define _Controls4U_ImgCtrl_h_ - -#define MAX_STEP 0.5 -#define MIN_ZOOM_FACTOR 0.1 -#define MAX_ZOOM_FACTOR 5.00 - -class ImgCtrl : public Ctrl { -public: - typedef ImgCtrl CLASSNAME; - ImgCtrl(); - - void Zoom(double m_fStep); - void Fit(); - void RealSize(); - - void SetStepZoomFactor(double f_step); - void SetZoomVisible(bool b_show); - void SetThumbVisible(bool _thumb); - - Image &GetImage() {return image;}; - void SetImage(ImageBuffer img); - void SetImage(Image img); - void SetImage(const char *fileName); - - virtual void MouseWheel(Point p, int zdelta, dword keyflags); - virtual void RightDown(Point p, dword keyflags); - - virtual void LeftDown(Point p, dword keyflags); - virtual void LeftUp(Point p, dword keyflags); - virtual void MouseMove(Point p, dword keyflags); - - int GetHeight() {return image.GetHeight();}; - int GetWidth() {return image.GetWidth();}; - void GetRectRep(double &left, double &top, double &width, double &height); - void GetRepXY(double x, double y, int &repx, int &repy); - void GetXYRep(int repx, int repy, double &x, double &y); - - void Load(const WString str_img_path); - bool Save(String fileName, String ext, int qualityBpp = -1); - void Print(int n_draw_origin_x=0,int n_draw_origin_y=0,int n_image_cx=1000,int n_image_cy=1000); - - bool IsEmpty(); - - void BW(); - - virtual void Paint(Draw& w); - -private: - void LocalMenu(Bar& bar); - - double x0, y0; //Coordenada origem para desenho - double xDelta, yDelta; //Guarda o ultimo deslocamento em relação ao 0,0 - - int width, height; - - Image image; - Image imageRep; - double factor; - - bool moving; - Point lastPoint; - bool showZoom; - bool thumb; -}; - -#endif diff --git a/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tpp b/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tpp index 079dc21b7..56c29be26 100644 --- a/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tpp +++ b/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tpp @@ -4,7 +4,9 @@ topic "News and changes log"; [{_}%EN-US [s0; [*R+184 Controls4U. News and changes log]&] [s0;%- &] -[ {{1441:8559f0;g0;^t/25b/25 [s0;# [2 2011/07/26]] +[ {{1441:8559f0;g0;^t/25b/25 [s0;# [2 2011/08/27]] +:: [s0; [2 Added PainterCanvas]] +:: [s0;# [2 2011/07/26]] :: [s0; [2 Removed internal MyBufferPainter]] :: [s0;# [2 2011/07/24]] :: [s0; [2 Added SliderCtrlX and StarIndicator]] diff --git a/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tppi b/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tppi index af7f5d0e3..7295d88e5 100644 --- a/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tppi +++ b/bazaar/Controls4U/srcdoc.tpp/ChangesLog$en-us.tppi @@ -1,6 +1,6 @@ TITLE("News and changes log") COMPRESSED -120,156,133,84,127,79,219,48,16,253,42,39,1,19,99,131,196,249,81,218,244,175,210,49,169,154,96,19,29,19,82,149,129,27,95,91,139,212,70,182,3,67,136,239,190,115,82,160,25,173,86,169,82,98,223,123,119,247,222,93,38,176,187,27,126,14,119,194,255,252,178,47,56,227,85,233,242,9,239,198,253,131,139,14,225,24,225,98,22,179,144,117,162,228,56,137,194,56,140,18,22,165,172,219,77,216,113,218,141,123,157,78,86,240,59,39,181,202,39,79,215,207,123,167,231,135,151,99,152,216,176,15,147,131,139,79,172,155,192,80,43,103,116,105,147,203,35,56,199,7,11,92,9,40,22,92,205,209,66,169,231,249,135,220,199,239,29,2,61,192,211,19,75,18,150,117,211,180,55,11,251,243,176,255,219,5,81,58,165,127,205,186,3,147,8,162,144,177,32,60,14,162,78,158,103,217,42,91,4,23,184,212,247,40,64,42,135,70,241,18,206,30,79,170,217,12,205,15,94,31,189,6,183,73,146,22,201,64,8,162,24,151,82,160,25,58,83,94,213,229,142,29,55,35,37,100, -193,157,222,194,195,216,6,158,145,253,197,137,106,255,227,209,38,80,28,68,113,11,52,172,85,33,216,233,159,187,82,27,52,39,70,63,88,52,160,248,18,193,105,24,213,173,161,251,231,254,61,123,24,132,221,205,37,125,83,122,10,69,227,201,70,92,103,51,110,140,142,84,112,149,245,117,12,10,39,239,241,234,133,199,110,36,74,131,184,77,68,238,195,82,11,4,43,213,188,164,134,22,6,185,168,29,3,46,132,244,99,228,217,151,52,134,242,237,118,255,236,39,233,215,76,73,77,63,162,168,133,180,80,112,139,112,134,36,9,144,112,130,24,23,220,130,210,14,44,42,75,116,247,210,61,190,248,231,100,49,44,117,113,235,27,25,84,62,139,175,68,54,241,220,247,195,29,138,45,141,172,13,201,206,155,36,175,42,148,220,90,124,47,66,216,11,88,20,68,189,150,8,77,41,163,37,159,35,136,102,229,96,202,139,219,185,209,149,95,12,77,198,250,178,156,225,202,222,113,131,202,181,154,95,195,103,171,58,46,45,14,236,201,43,199,254,199,186,103,179,90,135,58,244,171,116, -55,89,246,22,179,173,214,180,125,190,85,183,202,250,229,69,107,41,141,213,149,41,182,183,31,111,167,244,110,209,76,172,51,103,100,45,146,162,254,90,104,108,236,81,72,125,80,192,20,41,221,140,50,46,232,157,192,210,129,169,148,133,233,35,61,90,44,103,91,106,96,233,38,251,40,237,119,35,73,95,238,7,111,165,26,29,158,42,97,233,173,242,83,10,168,170,165,79,101,171,57,125,175,104,66,124,50,10,52,40,111,174,21,119,92,113,124,191,71,77,218,48,106,159,15,105,160,61,195,218,23,49,207,159,159,27,115,33,255,11,147,243,185,205, +120,156,133,84,253,79,219,48,16,253,87,78,2,38,198,6,137,243,209,143,244,167,210,49,169,154,96,19,29,19,82,149,129,155,92,91,139,212,70,182,83,134,16,255,251,206,73,129,118,36,90,165,74,137,125,239,189,187,119,119,153,194,254,190,255,217,223,243,255,243,75,190,224,156,151,133,77,167,188,23,14,142,46,59,132,99,132,11,89,200,124,214,9,162,110,20,248,161,31,68,44,136,89,175,23,177,110,220,11,251,157,78,146,241,123,43,148,76,167,79,55,207,7,103,23,199,87,19,152,26,127,0,211,163,203,79,172,23,193,72,73,171,85,97,162,171,19,184,192,7,3,92,230,144,45,185,92,160,129,66,45,210,15,169,139,63,56,6,122,128,167,39,22,69,44,233,197,113,127,238,15,22,254,224,183,245,130,120,70,255,138,117,15,166,1,4,62,99,158,223,243,130,110,154,38,201,70,45,128,97,158,99,14,63,184,144,22,245,136,203,53,55,175,247,91,184,174,23,116,118,112,151,184,82,107,66,86,56,201,11,56,127,60,45,231,115,212,27,170,22,146,168,65,124,82,136, +156,180,173,46,174,171,50,39,150,235,177,204,69,198,173,106,225,97,172,129,103,108,126,113,162,58,252,120,210,4,10,189,32,220,1,141,42,55,9,118,246,231,190,80,26,245,169,86,15,6,53,72,190,66,176,10,198,85,105,104,255,185,127,207,238,59,95,27,83,250,38,213,12,178,186,151,141,184,78,51,110,130,150,92,176,165,113,121,12,51,43,214,120,253,194,99,26,137,98,47,220,37,162,169,129,149,202,17,140,144,139,130,10,90,106,228,121,213,49,224,121,46,220,248,57,246,21,141,175,120,187,61,60,255,73,254,213,211,85,209,143,41,106,41,12,100,220,32,156,35,89,2,100,92,78,140,75,110,64,42,11,6,165,33,186,181,176,143,47,253,179,34,27,21,42,187,115,133,12,75,167,226,50,17,117,60,119,245,112,139,121,75,33,91,67,178,247,102,201,171,11,5,55,6,223,155,224,247,61,22,120,65,127,199,132,58,149,241,138,47,16,242,122,85,97,198,179,187,133,86,165,91,40,69,141,117,105,89,205,165,185,231,26,165,221,41,126,11,159,108,242,184,50,56,52,167, +175,28,135,31,171,154,245,102,29,170,208,175,194,222,38,201,91,76,91,174,241,238,121,171,111,165,113,75,143,198,144,140,81,165,206,218,203,15,219,41,93,183,104,38,182,153,19,106,45,146,163,238,58,87,88,183,71,34,213,65,1,51,36,185,57,41,46,233,157,192,194,130,46,165,129,217,35,61,26,44,230,45,57,176,184,169,125,36,251,93,11,242,151,187,193,219,184,70,135,103,50,55,244,86,186,41,5,148,229,202,73,153,114,65,223,57,154,16,39,70,129,26,197,237,141,228,150,75,142,239,247,168,150,245,131,221,243,17,13,180,99,216,250,146,166,233,243,115,221,92,72,255,2,7,222,201,172,