RichEdit: Diagram

This commit is contained in:
Mirek Fidler 2025-07-14 09:54:04 +02:00
parent 987582e88a
commit a8c3be8dc6
11 changed files with 358 additions and 276 deletions

View file

@ -311,27 +311,27 @@ void ToolButton::LeftDown(Point, dword)
{
Refresh();
if(repeat)
WhenAction();
Action();
}
void ToolButton::LeftRepeat(Point, dword)
{
Refresh();
if(repeat)
WhenAction();
Action();
}
void ToolButton::LeftUp(Point, dword)
{
Refresh();
if(!repeat)
WhenAction();
Action();
}
bool ToolButton::HotKey(dword key)
{
if(key == accel) {
WhenAction();
Action();
return true;
}
return false;

View file

@ -55,22 +55,26 @@ void DiagramEditor::TheBar(Bar& bar)
bar.Add(line_dash, DPI(50));
bar.Add(ink);
bar.Add(paper);
bar.Gap();
bar.Separator();
Size isz = IconSz();
DiagramItem m;
m.pt[0] = Point(2, 2);
m.pt[1] = Point(isz.cx - 2, isz.cy - 2);
m.width = ~line_width;
m.dash = ~line_dash;
m.shape = ~shape;
m.ink = ~ink;
m.paper = ~paper;
m.cap[0] = ~line_start;
m.cap[1] = ~line_end;
bar.Add(MakeIcon(m, isz), [=]{
for(int i = 0; i < tool_count; i++) {
DiagramItem m = tl[i];
m.pt[0] = Point(2, 2);
m.pt[1] = Point(isz.cx - 2, isz.cy - 2);
m.width = log(m.width + 1);
bar.Add(MakeIcon(m, isz), [=] {
CancelSelection();
if(tool == i)
tool = -1;
else {
tool = i;
GetAttrs(tl[i]);
}
SetBar();
// SetAttrs();
});
})
.Key(get_i(i, K_1, K_2, K_3, K_4))
.Check(tool == i);
}
bar.Break();
// ink.DarkContent(IsDarkContent());
text_editor.FontTools(bar);

View file

@ -1,22 +0,0 @@
#include "RichEdit.h"
namespace Upp {
void DiagramEditor::SetCursor(int i)
{
cursor = i;
if(i < 0)
return;
sel.FindAdd(i);
GetAttrs();
}
DiagramItem& DiagramEditor::CursorItem()
{
static DiagramItem nil;
if(cursor >= 0 && cursor < data.item.GetCount())
return data.item[cursor];
return nil;
}
}

View file

@ -96,6 +96,9 @@ DiagramEditor::DiagramEditor()
for(int i = 0; i < 10; i++)
line_width.Add(i);
line_width << [=] { SetAttrs(ATTR_WIDTH); };
tl[0].shape = DiagramItem::SHAPE_LINE;
tl[1].shape = DiagramItem::SHAPE_ROUNDRECT;
ResetUndo();
Sync();
@ -112,22 +115,20 @@ Image DiagramEditor::MakeIcon(DiagramItem& m, Size isz)
{
struct IconMaker : ImageMaker {
Size isz;
DiagramItem& m;
DiagramItem m;
String Key() const override {
return StoreAsString(m) + String((byte *)&isz, sizeof(isz));
return StoreAsString(const_cast<DiagramItem&>(m)) + String((byte *)&isz, sizeof(isz));
}
Image Make() const override {
ImagePainter iw(isz);
iw.Scale(DPI(1));
iw.Clear();
m.Paint(iw);
return iw;
}
IconMaker(DiagramItem& m) : m(m) {}
};
IconMaker mk(m);
IconMaker mk;
mk.m = m;
mk.isz = isz;
return MakeImage(mk);
}
@ -181,8 +182,10 @@ void DiagramEditor::Paint(Draw& w)
Size dsz = data.GetSize();
iw.Move(dsz.cx, 0).Line(dsz.cx, dsz.cy).Line(0, dsz.cy).Stroke(0.2, SColorHighlight());
if(data.item.GetCount() == 0)
iw.DrawText(DPI(30), DPI(30), "Right-click to insert item(s)", ArialZ(30).Italic(), SLtGray());
if(data.item.GetCount() == 0) {
iw.DrawText(DPI(30), DPI(30), "Right-click to insert item(s)", ArialZ(10).Italic(), SLtGray());
iw.DrawText(DPI(30), DPI(50), "Double-click to edit text", ArialZ(10).Italic(), SLtGray());
}
if(display_grid)
for(int x = 0; x < dsz.cx; x += 8)
@ -313,4 +316,22 @@ void DiagramEditor::Reset()
Sync();
}
bool DiagramEditor::Key(dword key, int count)
{
switch(key) {
case K_ESCAPE:
if(tool >= 0) {
tool = -1;
SetBar();
return true;
}
if(IsCursor()) {
KillCursor();
return true;
}
break;
}
return Ctrl::Key(key, count);
}
}

View file

@ -46,6 +46,7 @@ public:
void RightUp(Point p, dword keyflags) override;
void HorzMouseWheel(Point p, int zdelta, dword keyflags) override;
void MouseWheel(Point p, int zdelta, dword keyflags) override;
bool Key(dword key, int count) override;
void Layout() override;
private:
@ -68,16 +69,21 @@ private:
int pi; // point index
};
bool moving = false; // moving hysteresis
Vector<Cn> conns; // connections, created at the drag start, updates line connections
BinUndoRedo undoredo;
int tool = 0;
ToolBar toolbar;
DropList shape, line_start, line_end, line_width, line_dash;
DiaRichEdit text_editor;
ColorButton ink, paper;
int tool = -1;
int tool_count = 2; // TODO
DiagramItem tl[2];
ScrollBars sb;
@ -114,6 +120,8 @@ private:
Image DashIcon(int i);
void PrepareConns();
void UseConns();
void Grid(int shape, Point& p);
void Grid(const DiagramItem& m, Point& p) { Grid(m.shape, p); }
void FixPositions();
@ -127,9 +135,13 @@ private:
ATTR_PAPER = 0x0040,
ATTR_ALL = 0xffffffff
};
void SetAttrs(DiagramItem& m, dword attrs);
void SetAttrs(dword attr);
void GetAttrs(const DiagramItem& m);
void GetAttrs();
DiagramItem& AddItem(int shape);
void Copy();
void Cut();
void Paste();

View file

@ -92,12 +92,19 @@ Image DiagramEditor::CursorImage(Point p, dword keyflags)
void DiagramEditor::LeftDouble(Point p, dword keyflags)
{
if(IsCursor())
if(IsCursor() && !(keyflags & K_CTRL))
StartText();
}
void DiagramEditor::Grid(int shape, Point& p)
{
p = shape == DiagramItem::SHAPE_LINE ? p / 8 * 8 : p / 16 * 16;
}
void DiagramEditor::LeftDown(Point p, dword keyflags)
{
moving = false;
conns.Clear();
Map(p);
@ -106,6 +113,17 @@ void DiagramEditor::LeftDown(Point p, dword keyflags)
dragstart = dragcurrent = p;
SetCapture();
if(tool >= 0) {
KillCursor();
DiagramItem& m = AddItem(tl[tool].shape);
m = tl[tool];
Grid(m, p);
m.pt[0] = m.pt[1] = p;
m.FixPosition();
draghandle = Point(1, 1);
return;
}
if(IsCursor()) {
Point h = GetHandle(cursor, p);
@ -124,14 +142,24 @@ void DiagramEditor::LeftDown(Point p, dword keyflags)
int i = FindItem(p);
if(i >= 0) {
SetCursor(i);
dragfrom = GetCursorRect();
if(dragfrom.Contains(p)) {
sdragfrom.SetCount(sel.GetCount());
for(int i = 0; i < sel.GetCount(); i++)
sdragfrom[i] = data.item[sel[i]];
PrepareConns();
draghandle = Null;
if((keyflags & K_CTRL) && sel.Find(i) >= 0) {
sel.RemoveKey(i);
if(sel.GetCount())
SetCursor(sel.Top());
else
KillCursor();
}
else
SetCursor(i);
if(IsCursor()) {
dragfrom = GetCursorRect();
if(dragfrom.Contains(p)) {
sdragfrom.SetCount(sel.GetCount());
for(int i = 0; i < sel.GetCount(); i++)
sdragfrom[i] = data.item[sel[i]];
PrepareConns();
draghandle = Null;
}
}
}
else {
@ -163,10 +191,10 @@ void DiagramEditor::MouseMove(Point p, dword keyflags)
Sync();
return;
}
if(HasCapture() && IsCursor()) {
if(HasCapture() && IsCursor() && (moving || Distance(dragstart, p) >= 8)) {
moving = true;
DiagramItem& m = CursorItem();
if(grid)
p = m.IsLine() ? p / 8 * 8 : p / 16 * 16;
Grid(m, p);
if(IsNull(draghandle)) { // move selection
Rectf to = dragfrom.Offseted(p - dragstart);
Pointf tp = to.TopLeft();
@ -199,23 +227,16 @@ void DiagramEditor::MouseMove(Point p, dword keyflags)
}
}
void DiagramEditor::LeftUp(Point p, dword keyflags)
void DiagramEditor::LeftUp(Point, dword)
{
conns.Clear();
Map(p);
Sync();
doselection = false;
moving = doselection = false;
Commit();
// if(Distance(dragstart, p) < 2 && CursorItem().IsTextClick(p))
// StartText();
}
void DiagramEditor::RightDown(Point p, dword keyflags)
{
LeftDown(p, keyflags);
Map(p);
auto PopPaint = [=](Draw& w, const Image& m, bool sel) {
@ -228,10 +249,12 @@ void DiagramEditor::RightDown(Point p, dword keyflags)
};
FinishText();
if(IsCursor()) {
DiagramItem& m = CursorItem();
int ii = FindItem(p);
if(ii >= 0) {
DiagramItem& m = data.item[ii];
if(m.IsLine()) {
SetCursor(ii);
Point h = GetHandle(cursor, p);
if(h.x) {
int i = h.x > 0;
@ -284,9 +307,8 @@ void DiagramEditor::RightDown(Point p, dword keyflags)
CancelSelection();
if(grid)
p = p / 16 * 16;
Pointf cp = Null;
Grid(si, p);
Pointf cp = Null; // connect line with nearest connection point
if(si == DiagramItem::SHAPE_LINE) {
double mind = DBL_MAX;
for(const DiagramItem& m : data.item)
@ -299,17 +321,10 @@ void DiagramEditor::RightDown(Point p, dword keyflags)
}
}
int i = data.item.GetCount();
if(si == 0) { // insert lines before shapes
i = 0;
while(i < data.item.GetCount() && data.item[i].IsLine())
i++;
data.item.Insert(i);
}
DiagramItem& m = data.item.At(i);
DiagramItem& m = AddItem(si);
if(IsNull(cp)) {
m.pt[0] = Pointf(p) - Pointf(64, 32);
m.pt[1] = Pointf(p) + Pointf(64, 32);
m.pt[0] = p;
m.pt[1] = p + Point(128, 64);
}
else {
m.pt[0] = cp;
@ -317,7 +332,6 @@ void DiagramEditor::RightDown(Point p, dword keyflags)
}
SetAttrs(ATTR_ALL);
m.shape = si;
SetCursor(i);
Sync();
}

View file

@ -2,32 +2,69 @@
namespace Upp {
void DiagramEditor::SetCursor(int i)
{
cursor = i;
if(i < 0) {
sel.Clear();
return;
}
sel.FindAdd(i);
GetAttrs();
}
DiagramItem& DiagramEditor::CursorItem()
{
static DiagramItem nil;
if(cursor >= 0 && cursor < data.item.GetCount())
return data.item[cursor];
return nil;
}
DiagramItem& DiagramEditor::AddItem(int shape)
{
int i = data.item.GetCount();
if(shape == 0) { // insert lines before shapes
i = 0;
while(i < data.item.GetCount() && data.item[i].IsLine())
i++;
data.item.Insert(i);
}
DiagramItem& m = data.item.At(i);
SetCursor(i);
return m;
}
void DiagramEditor::SetAttrs(DiagramItem& m, dword attrs)
{
if(attrs & ATTR_SHAPE)
m.shape = ~shape;
if(attrs & ATTR_CAP0)
m.cap[0] = ~line_start;
if(attrs & ATTR_CAP1)
m.cap[1] = ~line_end;
if(attrs & ATTR_WIDTH)
m.width = ~line_width;
if(attrs & ATTR_DASH)
m.dash = ~line_dash;
if(attrs & ATTR_INK)
m.ink = ~ink;
if(attrs & ATTR_PAPER)
m.paper = ~paper;
}
void DiagramEditor::SetAttrs(dword attrs)
{
for(int i = 0; i < sel.GetCount(); i++) {
DiagramItem& m = data.item[sel[i]];
if(attrs & ATTR_SHAPE)
m.shape = ~shape;
if(attrs & ATTR_CAP0)
m.cap[0] = ~line_start;
if(attrs & ATTR_CAP1)
m.cap[1] = ~line_end;
if(attrs & ATTR_WIDTH)
m.width = ~line_width;
if(attrs & ATTR_DASH)
m.dash = ~line_dash;
if(attrs & ATTR_INK)
m.ink = ~ink;
if(attrs & ATTR_PAPER)
m.paper = ~paper;
}
for(int i = 0; i < sel.GetCount(); i++)
SetAttrs(data.item[sel[i]], attrs);
if(tool >= 0)
SetAttrs(tl[tool], attrs);
Sync();
Commit();
}
void DiagramEditor::GetAttrs()
void DiagramEditor::GetAttrs(const DiagramItem& m)
{
DiagramItem& m = CursorItem();
shape <<= m.shape;
line_start <<= m.cap[0];
line_end <<= m.cap[1];
@ -37,6 +74,12 @@ void DiagramEditor::GetAttrs()
paper <<= m.paper;
}
void DiagramEditor::GetAttrs()
{
GetAttrs(CursorItem());
}
void DiagramEditor::MoveFrontBack(bool back)
{
FinishText();

View file

@ -31,10 +31,9 @@ file
DiagramEditor.h,
DiagramEditor.cpp,
DiagramMouse.cpp,
DiagramCursor.cpp,
DiagramOps.cpp,
ColumnPopUp.cpp,
Bar.cpp,
DiagramBar.cpp,
Text.cpp,
DiagramClip.cpp,
Diagram.iml,

View file

@ -56,31 +56,12 @@ void DiagramItem::FixPosition()
pt[0].y -= y;
pt[1].y -= y;
}
/* Sizef sz = GetRect().GetSize();
if(max(sz.cx, sz.cy) < 8) {
auto Fix = [](double& a1, double& a2) {
int d = a2 - a1;
if(abs(d) < 8)
a2 = a1 + sgn(d) * 8;
};
Fix(pt[0].x, pt[1].x);
Fix(pt[0].y, pt[1].y);
}
*/
}
Vector<Pointf> DiagramItem::GetConnections() const
{
Vector<Pointf> p;
if(IsLine()) {
p << pt[0] << pt[1];
return p;
}
Rectf r = GetRect();
p << r.TopCenter() << r.BottomCenter();
if(shape != SHAPE_PARALLELOGRAM)
p << r.CenterLeft() << r.CenterRight();
return p;
if(IsLine())
return;
if(pt[1].x - pt[0].x < 8)
pt[1].x = pt[0].x + 8;
if(pt[1].y - pt[0].y < 8)
pt[1].y = pt[0].y + 8;
}
bool DiagramItem::IsClick(Point p) const
@ -147,149 +128,6 @@ Rect DiagramItem::GetTextEditRect() const
return GetRect();
}
void DiagramItem::Paint(Painter& w, dword style, const Index<Pointf> *conn) const
{
Zoom zoom = Diagram::TextZoom();
RichText txt = ParseQTF(qtf);
static Vector<double> dashes[5] = { { 0 }, { 1, 1 }, { 2 }, { 1, 2 }, { 1, 2 } };
auto DoDash = [&] {
if(dash) {
Vector<double> d = clone(dashes[clamp(dash, 0, __countof(dashes))]);
for(double& h : d)
h *= width;
w.Dash(d, 0);
}
};
RGBA sel1 = 150 * SColorHighlight();
RGBA sel2 = 150 * Gray();
if(IsLine()) {
Pointf v = pt[1] - pt[0];
if(style) {
w.Move(pt[0]).Line(pt[1]).EndPath();
w.Begin();
if((style & EDITOR) && width == 0)
w.Dash("5 1").Stroke(1, 100 * sel2);
if(style & (Display::CURSOR | Display::SELECT)) {
w.LineCap(LINECAP_ROUND).Stroke(width + 12, (style & Display::SELECT ? 30 : 200) * sel2);
double r = (width + 12) / 2 - 1;
w.Circle(pt[0], r).Fill(sel1);
w.Circle(pt[1], r).Fill(sel1);
}
w.End();
}
double d = Length(v);
v = Upp::Normalize(v);
Pointf a1 = pt[0];
Pointf a2 = pt[1];
if(d > 4 * width) { // enough length to have caps
if(cap[0] == CAP_ARROW)
a1 += v * 4 * width;
if(cap[1] == CAP_ARROW)
a2 -= v * 4 * width;
}
w.Move(a1).Line(a2);
DoDash();
w.Stroke(width, ink);
Pointf o = Orthogonal(v);
if(d > 4 * width) {
auto PaintCap = [&](int k, Pointf p, Pointf a) {
Pointf oo = max(3.0, width * 2) * o;
switch(k) {
case CAP_NONE:
w.Circle(p, width / 2).Fill(ink);
break;
case CAP_ARROW:
w.Move(p).Line(a + oo).Line(a - oo).Fill(ink);
break;
case CAP_CIRCLE:
w.Circle(p, 5).Fill(ink);
break;
}
};
PaintCap(cap[0], pt[0], a1 + v);
PaintCap(cap[1], pt[1], a2 - v);
}
int cx = Distance(pt[0], pt[1]);
int txt_cy = txt.GetHeight(zoom, cx);
w.Begin();
double angle = Bearing(pt[1] - pt[0]);
if(angle >= -M_PI / 2 && angle <= M_PI / 2) {
w.Translate(pt[0] - o * (txt_cy + 10));
w.Rotate(angle);
}
else {
w.Translate(pt[1] + o * (txt_cy + 10));
w.Rotate(angle + M_PI);
}
txt.Paint(zoom, w, 0, 0, cx);
w.End();
}
else {
if(style & (Display::CURSOR | Display::SELECT)) {
w.RoundedRectangle(GetRect(), 5)
.Fill((style & Display::SELECT ? 30 : 200) * sel2);
w.RoundedRectangle(GetRect().Inflated(2), 5)
.Stroke(6, (style & Display::SELECT ? 30 : 200) * sel1);
}
int txt_cy = txt.GetHeight(zoom, GetRect().GetWidth());
Rectf r(pt[0], pt[1]);
r.Normalize();
r.Deflate(width / 2);
Pointf c = r.CenterPoint();
int sz = min(r.Width(), r.Height());
switch(shape) {
case SHAPE_ROUNDRECT:
w.RoundedRectangle(r.left, r.top, r.GetWidth(), r.GetHeight(), sz > 30 ? 8 : sz > 15 ? 4 : 2);
break;
case SHAPE_OVAL:
if(r.GetWidth() > r.GetHeight()) {
double ra = r.GetHeight() / 2;
w.Move(r.left + ra, r.top)
.Line(r.right - ra, r.top)
.Arc(r.right - ra, r.top + ra, ra, -M_PI / 2, M_PI)
.Line(r.left + ra, r.bottom)
.Arc(r.left + ra, r.top + ra, ra, M_PI / 2, M_PI);
break;
}
case SHAPE_ELLIPSE:
w.Ellipse(r);
break;
case SHAPE_DIAMOND:
w.Move(c.x, r.top).Line(r.right, c.y).Line(c.x, r.bottom).Line(r.left, c.y).Close();
break;
case SHAPE_PARALLELOGRAM:
w.Move(r.left + r.Width() / 6, r.top).Line(r.right, r.top)
.Line(r.right - r.Width() / 6, r.bottom).Line(r.left, r.bottom).Close();
break;
default:
w.Rectangle(r);
break;
}
DoDash();
w.Fill(paper).Stroke(width, ink);
txt.Paint(zoom, w, r.left, r.top + (r.GetHeight() - txt_cy) / 2, r.GetWidth());
if(style & GRID)
for(Pointf p : GetConnections()) {
w.Circle(p, 5);
if(conn && conn->Find(p) >= 0)
w.Fill(128 * SYellow());
w.Stroke(1, 190 * SColorHighlight());
}
}
}
void DiagramItem::Save(StringBuffer& r) const
{
r << Shape[clamp(shape, 0, Shape.GetCount() - 1)] << ' ';

View file

@ -0,0 +1,172 @@
#include "RichText.h"
namespace Upp {
Vector<Pointf> DiagramItem::GetConnections() const
{
Vector<Pointf> p;
if(IsLine()) {
p << pt[0] << pt[1];
return p;
}
Rectf r = GetRect();
p << r.TopCenter() << r.BottomCenter();
if(shape != SHAPE_PARALLELOGRAM)
p << r.CenterLeft() << r.CenterRight();
return p;
}
void DiagramItem::Paint(Painter& w, dword style, const Index<Pointf> *conn) const
{
Zoom zoom = Diagram::TextZoom();
RichText txt = ParseQTF(qtf);
static Vector<double> dashes[5] = { { 0 }, { 1, 1 }, { 2 }, { 1, 2 }, { 1, 2 } };
auto DoDash = [&] {
if(dash) {
Vector<double> d = clone(dashes[clamp(dash, 0, __countof(dashes))]);
for(double& h : d)
h *= width;
w.Dash(d, 0);
}
};
RGBA sel1 = 150 * SColorHighlight();
RGBA sel2 = 150 * Gray();
auto Stroke = [&] {
if(width)
w.Stroke(width, ink);
else
if(style & GRID)
w.Stroke(0.2, sel1);
};
if(IsLine()) {
Pointf v = pt[1] - pt[0];
if(style) {
w.Move(pt[0]).Line(pt[1]).EndPath();
w.Begin();
if((style & EDITOR) && width == 0)
w.Dash("5 1").Stroke(1, 100 * sel2);
if(style & (Display::CURSOR | Display::SELECT)) {
w.LineCap(LINECAP_ROUND).Stroke(width + 12, (style & Display::SELECT ? 30 : 200) * sel2);
double r = (width + 12) / 2 - 1;
w.Circle(pt[0], r).Fill(sel1);
w.Circle(pt[1], r).Fill(sel1);
}
w.End();
}
double d = Length(v);
v = Upp::Normalize(v);
Pointf a1 = pt[0];
Pointf a2 = pt[1];
if(d > 4 * width) { // enough length to have caps
if(cap[0] == CAP_ARROW)
a1 += v * 4 * width;
if(cap[1] == CAP_ARROW)
a2 -= v * 4 * width;
}
w.Move(a1).Line(a2);
DoDash();
Stroke();
Pointf o = Orthogonal(v);
if(d > 4 * width) {
auto PaintCap = [&](int k, Pointf p, Pointf a) {
Pointf oo = max(3.0, width * 2) * o;
switch(k) {
case CAP_NONE:
w.Circle(p, width / 2).Fill(ink);
break;
case CAP_ARROW:
w.Move(p).Line(a + oo).Line(a - oo).Fill(ink);
break;
case CAP_CIRCLE:
w.Circle(p, 5).Fill(ink);
break;
}
};
PaintCap(cap[0], pt[0], a1 + v);
PaintCap(cap[1], pt[1], a2 - v);
}
int cx = Distance(pt[0], pt[1]);
int txt_cy = txt.GetHeight(zoom, cx);
w.Begin();
double angle = Bearing(pt[1] - pt[0]);
if(angle >= -M_PI / 2 && angle <= M_PI / 2) {
w.Translate(pt[0] - o * (txt_cy + 10));
w.Rotate(angle);
}
else {
w.Translate(pt[1] + o * (txt_cy + 10));
w.Rotate(angle + M_PI);
}
txt.Paint(zoom, w, 0, 0, cx);
w.End();
}
else {
if(style & (Display::CURSOR | Display::SELECT)) {
w.RoundedRectangle(GetRect(), 5)
.Fill((style & Display::SELECT ? 30 : 200) * sel2);
w.RoundedRectangle(GetRect().Inflated(2), 5)
.Stroke(6, (style & Display::SELECT ? 30 : 200) * sel1);
}
int txt_cy = txt.GetHeight(zoom, GetRect().GetWidth());
Rectf r(pt[0], pt[1]);
r.Normalize();
r.Deflate(width / 2);
Pointf c = r.CenterPoint();
int sz = min(r.Width(), r.Height());
switch(shape) {
case SHAPE_ROUNDRECT:
w.RoundedRectangle(r.left, r.top, r.GetWidth(), r.GetHeight(), sz > 30 ? 8 : sz > 15 ? 4 : 2);
break;
case SHAPE_OVAL:
if(r.GetWidth() > r.GetHeight()) {
double ra = r.GetHeight() / 2;
w.Move(r.left + ra, r.top)
.Line(r.right - ra, r.top)
.Arc(r.right - ra, r.top + ra, ra, -M_PI / 2, M_PI)
.Line(r.left + ra, r.bottom)
.Arc(r.left + ra, r.top + ra, ra, M_PI / 2, M_PI);
break;
}
case SHAPE_ELLIPSE:
w.Ellipse(r);
break;
case SHAPE_DIAMOND:
w.Move(c.x, r.top).Line(r.right, c.y).Line(c.x, r.bottom).Line(r.left, c.y).Close();
break;
case SHAPE_PARALLELOGRAM:
w.Move(r.left + r.Width() / 6, r.top).Line(r.right, r.top)
.Line(r.right - r.Width() / 6, r.bottom).Line(r.left, r.bottom).Close();
break;
default:
w.Rectangle(r);
break;
}
DoDash();
w.Fill(paper);
Stroke();
txt.Paint(zoom, w, r.left, r.top + (r.GetHeight() - txt_cy) / 2, r.GetWidth());
if(style & GRID)
for(Pointf p : GetConnections()) {
w.Circle(p, 5);
if(conn && conn->Find(p) >= 0)
w.Fill(128 * SYellow());
w.Stroke(1, 190 * SColorHighlight());
}
}
}
}

View file

@ -38,6 +38,7 @@ file
Diagram readonly separator,
Diagram.h,
Diagram.cpp,
DiagramShape.cpp,
RichDiagram.cpp,
Info readonly separator,
srcdoc.tpp,