Solvespace

Форк
0
/
style.cpp 
944 строки · 32.9 Кб
1
//-----------------------------------------------------------------------------
2
// Implementation of a cosmetic line style, which determines the color and
3
// other appearance of a line or curve on-screen and in exported files. Some
4
// styles are predefined, and others can be created by the user.
5
//
6
// Copyright 2008-2013 Jonathan Westhues.
7
//-----------------------------------------------------------------------------
8
#include "solvespace.h"
9

10
const Style::Default Style::Defaults[] = {
11
    { { ACTIVE_GRP },   "ActiveGrp",    RGBf(1.0, 1.0, 1.0), 1.5, 4, true,  StipplePattern::CONTINUOUS },
12
    { { CONSTRUCTION }, "Construction", RGBf(0.1, 0.7, 0.1), 1.5, 0, false, StipplePattern::CONTINUOUS },
13
    { { INACTIVE_GRP }, "InactiveGrp",  RGBf(0.5, 0.3, 0.0), 1.5, 3, true,  StipplePattern::CONTINUOUS },
14
    { { DATUM },        "Datum",        RGBf(0.0, 0.8, 0.0), 1.5, 0, true,  StipplePattern::CONTINUOUS },
15
    { { SOLID_EDGE },   "SolidEdge",    RGBf(0.8, 0.8, 0.8), 1.0, 2, true,  StipplePattern::CONTINUOUS },
16
    { { CONSTRAINT },   "Constraint",   RGBf(1.0, 0.1, 1.0), 1.0, 0, true,  StipplePattern::CONTINUOUS },
17
    { { SELECTED },     "Selected",     RGBf(1.0, 0.0, 0.0), 1.5, 0, true,  StipplePattern::CONTINUOUS },
18
    { { HOVERED },      "Hovered",      RGBf(1.0, 1.0, 0.0), 1.5, 0, true,  StipplePattern::CONTINUOUS },
19
    { { CONTOUR_FILL }, "ContourFill",  RGBf(0.0, 0.1, 0.1), 1.0, 0, true,  StipplePattern::CONTINUOUS },
20
    { { NORMALS },      "Normals",      RGBf(0.0, 0.4, 0.4), 1.0, 0, true,  StipplePattern::CONTINUOUS },
21
    { { ANALYZE },      "Analyze",      RGBf(0.0, 1.0, 1.0), 3.0, 0, true,  StipplePattern::CONTINUOUS },
22
    { { DRAW_ERROR },   "DrawError",    RGBf(1.0, 0.0, 0.0), 8.0, 0, true,  StipplePattern::CONTINUOUS },
23
    { { DIM_SOLID },    "DimSolid",     RGBf(0.1, 0.1, 0.1), 1.0, 0, true,  StipplePattern::CONTINUOUS },
24
    { { HIDDEN_EDGE },  "HiddenEdge",   RGBf(0.8, 0.8, 0.8), 1.0, 1, true,  StipplePattern::DASH },
25
    { { OUTLINE },      "Outline",      RGBf(0.8, 0.8, 0.8), 3.0, 5, true,  StipplePattern::CONTINUOUS },
26
    { { 0 },            NULL,           RGBf(0.0, 0.0, 0.0), 0.0, 0, true,  StipplePattern::CONTINUOUS }
27
};
28

29
std::string Style::CnfColor(const std::string &prefix) {
30
    return "Style_" + prefix + "_Color";
31
}
32
std::string Style::CnfWidth(const std::string &prefix) {
33
    return "Style_" + prefix + "_Width";
34
}
35
std::string Style::CnfStippleType(const std::string &prefix) {
36
    return "Style_" + prefix + "_StippleType";
37
}
38
std::string Style::CnfStippleScale(const std::string &prefix) {
39
    return "Style_" + prefix + "_StippleScale";
40
}
41
std::string Style::CnfTextHeight(const std::string &prefix) {
42
    return "Style_" + prefix + "_TextHeight";
43
}
44
std::string Style::CnfExportable(const std::string &prefix) {
45
    return "Style_" + prefix + "_Exportable";
46
}
47

48
std::string Style::CnfPrefixToName(const std::string &prefix) {
49
    std::string name = "#def-";
50

51
    for(size_t i = 0; i < prefix.length(); i++) {
52
        if(isupper(prefix[i]) && i != 0)
53
            name += '-';
54
        name += tolower(prefix[i]);
55
    }
56

57
    return name;
58
}
59

60
void Style::CreateAllDefaultStyles() {
61
    const Default *d;
62
    for(d = &(Defaults[0]); d->h.v; d++) {
63
        (void)Get(d->h);
64
    }
65
}
66

67
void Style::CreateDefaultStyle(hStyle h) {
68
    bool isDefaultStyle = true;
69
    const Default *d;
70
    for(d = &(Defaults[0]); d->h.v; d++) {
71
        if(d->h == h) break;
72
    }
73
    if(!d->h.v) {
74
        // Not a default style; so just create it the same as our default
75
        // active group entity style.
76
        d = &(Defaults[0]);
77
        isDefaultStyle = false;
78
    }
79

80
    Style ns = {};
81
    FillDefaultStyle(&ns, d);
82
    ns.h = h;
83
    if(isDefaultStyle) {
84
        ns.name = CnfPrefixToName(d->cnfPrefix);
85
    } else {
86
        ns.name = "new-custom-style";
87
    }
88

89
    SK.style.Add(&ns);
90
}
91

92
void Style::FillDefaultStyle(Style *s, const Default *d, bool factory) {
93
    Platform::SettingsRef settings = Platform::GetSettings();
94

95
    if(d == NULL) d = &Defaults[0];
96
    s->color         = (factory)
97
                        ? d->color
98
                        : settings->ThawColor(CnfColor(d->cnfPrefix), d->color);
99
    s->width         = (factory)
100
                        ? d->width
101
                        : settings->ThawFloat(CnfWidth(d->cnfPrefix), (float)(d->width));
102
    s->widthAs       = UnitsAs::PIXELS;
103
    s->textHeight    = (factory) ? 11.5
104
                                 : settings->ThawFloat(CnfTextHeight(d->cnfPrefix), 11.5);
105
    s->textHeightAs  = UnitsAs::PIXELS;
106
    s->textOrigin    = TextOrigin::NONE;
107
    s->textAngle     = 0;
108
    s->visible       = true;
109
    s->exportable    = (factory)
110
                        ? d->exportable
111
                        : settings->ThawBool(CnfExportable(d->cnfPrefix), d->exportable);
112
    s->filled        = false;
113
    s->fillColor     = RGBf(0.3, 0.3, 0.3);
114
    s->stippleType   = (factory)
115
                        ? d->stippleType
116
                        : Style::StipplePatternFromString(
117
                            settings->ThawString(CnfStippleType(d->cnfPrefix),
118
                            StipplePatternName(d->stippleType)));
119
    s->stippleScale  = (factory)
120
                        ? 15.0
121
                        : settings->ThawFloat(CnfStippleScale(d->cnfPrefix), 15.0);
122
    s->zIndex        = d->zIndex;
123
}
124

125
void Style::LoadFactoryDefaults() {
126
    const Default *d;
127
    for(d = &(Defaults[0]); d->h.v; d++) {
128
        Style *s = Get(d->h);
129
        FillDefaultStyle(s, d, /*factory=*/true);
130
    }
131
    SS.backgroundColor = RGBi(0, 0, 0);
132
}
133

134
void Style::FreezeDefaultStyles(Platform::SettingsRef settings) {
135
    const Default *d;
136
    for(d = &(Defaults[0]); d->h.v; d++) {
137
        settings->FreezeColor(CnfColor(d->cnfPrefix), Color(d->h));
138
        settings->FreezeFloat(CnfWidth(d->cnfPrefix), (float)Width(d->h));
139
        settings->FreezeString(CnfStippleType(d->cnfPrefix), StipplePatternName(d->h));
140
        settings->FreezeFloat(CnfStippleScale(d->cnfPrefix), (float)StippleScale(d->h));
141
        settings->FreezeFloat(CnfTextHeight(d->cnfPrefix), (float)TextHeight(d->h));
142
        settings->FreezeBool(CnfExportable(d->cnfPrefix), Exportable(d->h.v));
143
    }
144
}
145

146
uint32_t Style::CreateCustomStyle(bool rememberForUndo) {
147
    if(rememberForUndo) SS.UndoRemember();
148
    uint32_t vs = max((uint32_t)Style::FIRST_CUSTOM, SK.style.MaximumId() + 1);
149
    hStyle hs = { vs };
150
    (void)Style::Get(hs);
151
    return hs.v;
152
}
153

154
void Style::AssignSelectionToStyle(uint32_t v) {
155
    bool showError = false;
156
    SS.GW.GroupSelection();
157

158
    SS.UndoRemember();
159
    int i;
160
    for(i = 0; i < SS.GW.gs.entities; i++) {
161
        hEntity he = SS.GW.gs.entity[i];
162
        Entity *e = SK.GetEntity(he);
163
        if(!e->IsStylable()) continue;
164

165
        if(!he.isFromRequest()) {
166
            showError = true;
167
            continue;
168
        }
169

170
        hRequest hr = he.request();
171
        Request *r = SK.GetRequest(hr);
172
        r->style.v = v;
173
        SS.MarkGroupDirty(r->group);
174
    }
175
    for(i = 0; i < SS.GW.gs.constraints; i++) {
176
        hConstraint hc = SS.GW.gs.constraint[i];
177
        Constraint *c = SK.GetConstraint(hc);
178
        if(!c->IsStylable()) continue;
179

180
        c->disp.style.v = v;
181
        SS.MarkGroupDirty(c->group);
182
    }
183

184
    if(showError) {
185
        Error(_("Can't assign style to an entity that's derived from another "
186
                "entity; try assigning a style to this entity's parent."));
187
    }
188

189
    SS.GW.ClearSelection();
190
    SS.GW.Invalidate();
191

192
    // And show that style's info screen in the text window.
193
    SS.TW.GoToScreen(TextWindow::Screen::STYLE_INFO);
194
    SS.TW.shown.style.v = v;
195
    SS.ScheduleShowTW();
196
}
197

198
//-----------------------------------------------------------------------------
199
// Look up a style by its handle. If that style does not exist, then create
200
// the style, according to our table of default styles.
201
//-----------------------------------------------------------------------------
202
Style *Style::Get(hStyle h) {
203
    if(h.v == 0) h.v = ACTIVE_GRP;
204

205
    Style *s = SK.style.FindByIdNoOops(h);
206
    if(s) {
207
        // It exists, good.
208
        return s;
209
    } else {
210
        // It doesn't exist; so we should create it and then return that.
211
        CreateDefaultStyle(h);
212
        return SK.style.FindById(h);
213
    }
214
}
215

216
//-----------------------------------------------------------------------------
217
// A couple of wrappers, so that I can call these functions with either an
218
// hStyle or with the integer corresponding to that hStyle.v.
219
//-----------------------------------------------------------------------------
220
RgbaColor Style::Color(int s, bool forExport) {
221
    hStyle hs = { (uint32_t)s };
222
    return Color(hs, forExport);
223
}
224
double Style::Width(int s) {
225
    hStyle hs = { (uint32_t)s };
226
    return Width(hs);
227
}
228

229
//-----------------------------------------------------------------------------
230
// If a color is almost white, then we can rewrite it to black, just so that
231
// it won't disappear on file formats with a light background.
232
//-----------------------------------------------------------------------------
233
RgbaColor Style::RewriteColor(RgbaColor rgbin) {
234
    Vector rgb = Vector::From(rgbin.redF(), rgbin.greenF(), rgbin.blueF());
235
    rgb = rgb.Minus(Vector::From(1, 1, 1));
236
    if(rgb.Magnitude() < 0.4 && SS.fixExportColors) {
237
        // This is an almost-white color in a default style, which is
238
        // good for the default on-screen view (black bg) but probably
239
        // not desired in the exported files, which typically are shown
240
        // against white backgrounds.
241
        return RGBi(0, 0, 0);
242
    } else {
243
        return rgbin;
244
    }
245
}
246

247
//-----------------------------------------------------------------------------
248
// Return the stroke color associated with our style as 8-bit RGB.
249
//-----------------------------------------------------------------------------
250
RgbaColor Style::Color(hStyle h, bool forExport) {
251
    Style *s = Get(h);
252
    if(forExport) {
253
        return RewriteColor(s->color);
254
    } else {
255
        return s->color;
256
    }
257
}
258

259
//-----------------------------------------------------------------------------
260
// Return the fill color associated with our style as 8-bit RGB.
261
//-----------------------------------------------------------------------------
262
RgbaColor Style::FillColor(hStyle h, bool forExport) {
263
    Style *s = Get(h);
264
    if(forExport) {
265
        return RewriteColor(s->fillColor);
266
    } else {
267
        return s->fillColor;
268
    }
269
}
270

271
//-----------------------------------------------------------------------------
272
// Return the width associated with our style in pixels..
273
//-----------------------------------------------------------------------------
274
double Style::Width(hStyle h) {
275
    Style *s = Get(h);
276
    switch(s->widthAs) {
277
        case UnitsAs::MM:     return s->width * SS.GW.scale;
278
        case UnitsAs::PIXELS: return s->width;
279
    }
280
    ssassert(false, "Unexpected units");
281
}
282

283
//-----------------------------------------------------------------------------
284
// Return the width associated with our style in millimeters..
285
//-----------------------------------------------------------------------------
286
double Style::WidthMm(int hs) {
287
    double widthpx = Width(hs);
288
    return widthpx / SS.GW.scale;
289
}
290

291
//-----------------------------------------------------------------------------
292
// Return the associated text height, in pixels.
293
//-----------------------------------------------------------------------------
294
double Style::TextHeight(hStyle h) {
295
    Style *s = Get(h);
296
    switch(s->textHeightAs) {
297
        case UnitsAs::MM:     return s->textHeight * SS.GW.scale;
298
        case UnitsAs::PIXELS: return s->textHeight;
299
    }
300
    ssassert(false, "Unexpected units");
301
}
302

303
double Style::DefaultTextHeight() {
304
    hStyle hs { Style::CONSTRAINT };
305
    return TextHeight(hs);
306
}
307

308
//-----------------------------------------------------------------------------
309
// Return the parameters of this style, as a canvas stroke.
310
//-----------------------------------------------------------------------------
311
Canvas::Stroke Style::Stroke(hStyle hs) {
312
    Canvas::Stroke stroke = {};
313
    Style *style = Style::Get(hs);
314
    stroke.color = style->color;
315
    stroke.stipplePattern = style->stippleType;
316
    stroke.stippleScale = style->stippleScale;
317
    stroke.width = style->width;
318
    switch(style->widthAs) {
319
        case Style::UnitsAs::PIXELS:
320
            stroke.unit = Canvas::Unit::PX;
321
            break;
322
        case Style::UnitsAs::MM:
323
            stroke.unit = Canvas::Unit::MM;
324
            break;
325
    }
326
    return stroke;
327
}
328

329
Canvas::Stroke Style::Stroke(int hsv) {
330
    hStyle hs = { (uint32_t) hsv };
331
    return Style::Stroke(hs);
332
}
333

334
//-----------------------------------------------------------------------------
335
// Should lines and curves from this style appear in the output file? Only
336
// if it's both shown and exportable.
337
//-----------------------------------------------------------------------------
338
bool Style::Exportable(int si) {
339
    hStyle hs = { (uint32_t)si };
340
    Style *s = Get(hs);
341
    return (s->exportable) && (s->visible);
342
}
343

344
//-----------------------------------------------------------------------------
345
// Return the appropriate style for our entity. If the entity has a style
346
// explicitly assigned, then it's that style. Otherwise it's the appropriate
347
// default style.
348
//-----------------------------------------------------------------------------
349
hStyle Style::ForEntity(hEntity he) {
350
    Entity *e = SK.GetEntity(he);
351
    // If the entity has a special style, use that. If that style doesn't
352
    // exist yet, then it will get created automatically later.
353
    if(e->style.v != 0) {
354
        return e->style;
355
    }
356

357
    // Otherwise, we use the default rules.
358
    hStyle hs;
359
    if(e->group != SS.GW.activeGroup) {
360
        hs.v = INACTIVE_GRP;
361
    } else if(e->construction) {
362
        hs.v = CONSTRUCTION;
363
    } else {
364
        hs.v = ACTIVE_GRP;
365
    }
366
    return hs;
367
}
368

369
StipplePattern Style::StipplePatternFromString(std::string name) {
370
    std::transform(name.begin(), name.end(), name.begin(), ::tolower);
371
    if(name == "continuous") {
372
        return StipplePattern::CONTINUOUS;
373
    } else if(name == "shortdash") {
374
        return StipplePattern::SHORT_DASH;
375
    } else if(name == "dash") {
376
        return StipplePattern::DASH;
377
    } else if(name == "longdash") {
378
        return StipplePattern::LONG_DASH;
379
    } else if(name == "dashdot") {
380
        return StipplePattern::DASH_DOT;
381
    } else if(name == "dashdotdot") {
382
        return StipplePattern::DASH_DOT_DOT;
383
    } else if(name == "dot") {
384
        return StipplePattern::DOT;
385
    } else if(name == "freehand") {
386
        return StipplePattern::FREEHAND;
387
    } else if(name == "zigzag") {
388
        return StipplePattern::ZIGZAG;
389
    }
390

391
    return StipplePattern::CONTINUOUS;
392
}
393

394
StipplePattern Style::PatternType(hStyle hs) {
395
    Style *s = Get(hs);
396
    return s->stippleType;
397
}
398

399
std::string Style::StipplePatternName(hStyle hs) {
400
    Style *s = Get(hs);
401
    return StipplePatternName(s->stippleType);
402
}
403

404
std::string Style::StipplePatternName(StipplePattern stippleType) {
405
    switch(stippleType) {
406
        case StipplePattern::CONTINUOUS:   return "Continuous";
407
        case StipplePattern::SHORT_DASH:   return "ShortDash";
408
        case StipplePattern::DASH:         return "Dash";
409
        case StipplePattern::LONG_DASH:    return "LongDash";
410
        case StipplePattern::DASH_DOT:     return "DashDot";
411
        case StipplePattern::DASH_DOT_DOT: return "DashDotDot";
412
        case StipplePattern::DOT:          return "Dot";
413
        case StipplePattern::FREEHAND:     return "FreeHand";
414
        case StipplePattern::ZIGZAG:       return "ZigZag";
415
    }
416

417
    return "Continuous";
418
}
419

420
double Style::StippleScale(hStyle hs) {
421
    Style *s = Get(hs);
422
    return s->stippleScale;
423
}
424

425
double Style::StippleScaleMm(hStyle hs) {
426
    Style *s = Get(hs);
427
    if(s->widthAs == UnitsAs::MM) {
428
        return s->stippleScale;
429
    } else if(s->widthAs == UnitsAs::PIXELS) {
430
        return s->stippleScale / SS.GW.scale;
431
    }
432
    return 1.0;
433
}
434

435
std::string Style::DescriptionString() const {
436
    if(name.empty()) {
437
        return ssprintf("s%03x-(unnamed)", h.v);
438
    } else {
439
        return ssprintf("s%03x-%s", h.v, name.c_str());
440
    }
441
}
442

443

444
void TextWindow::ScreenShowListOfStyles(int link, uint32_t v) {
445
    SS.TW.GoToScreen(Screen::LIST_OF_STYLES);
446
}
447
void TextWindow::ScreenShowStyleInfo(int link, uint32_t v) {
448
    GraphicsWindow::MenuEdit(Command::UNSELECT_ALL);
449
    SS.TW.GoToScreen(Screen::STYLE_INFO);
450
    SS.TW.shown.style.v = v;
451
}
452

453
void TextWindow::ScreenLoadFactoryDefaultStyles(int link, uint32_t v) {
454
    Style::LoadFactoryDefaults();
455
    SS.TW.GoToScreen(Screen::LIST_OF_STYLES);
456
    SS.GW.persistentDirty = true;
457
}
458

459
void TextWindow::ScreenCreateCustomStyle(int link, uint32_t v) {
460
    Style::CreateCustomStyle();
461
}
462

463
void TextWindow::ScreenChangeBackgroundColor(int link, uint32_t v) {
464
    RgbaColor rgb = SS.backgroundColor;
465
    SS.TW.ShowEditControlWithColorPicker(3, rgb);
466
    SS.TW.edit.meaning = Edit::BACKGROUND_COLOR;
467
}
468

469
void TextWindow::ShowListOfStyles() {
470
    Printf(true, "%Ft color  style-name");
471

472
    bool darkbg = false;
473
    for(Style &s : SK.style) {
474
        Printf(false, "%Bp  %Bz   %Bp   %Fl%Ll%f%D%s%E",
475
            darkbg ? 'd' : 'a',
476
            &s.color,
477
            darkbg ? 'd' : 'a',
478
            ScreenShowStyleInfo, s.h.v,
479
            s.DescriptionString().c_str());
480

481
        darkbg = !darkbg;
482
    }
483

484
    Printf(true, "  %Fl%Ll%fcreate a new custom style%E",
485
        &ScreenCreateCustomStyle);
486

487
    Printf(false, "");
488

489
    RgbaColor rgb = SS.backgroundColor;
490
    Printf(false, "%Ft background color (r, g, b)%E");
491
    Printf(false, "%Ba   %@, %@, %@ %Fl%D%f%Ll[change]%E",
492
        rgb.redF(), rgb.greenF(), rgb.blueF(),
493
        top[rows-1] + 2, &ScreenChangeBackgroundColor);
494

495
    Printf(false, "");
496
    Printf(false, "  %Fl%Ll%fload factory defaults%E",
497
        &ScreenLoadFactoryDefaultStyles);
498
}
499

500

501
void TextWindow::ScreenChangeStyleName(int link, uint32_t v) {
502
    hStyle hs = { v };
503
    Style *s = Style::Get(hs);
504
    SS.TW.ShowEditControl(12, s->name);
505
    SS.TW.edit.style = hs;
506
    SS.TW.edit.meaning = Edit::STYLE_NAME;
507
}
508

509
void TextWindow::ScreenDeleteStyle(int link, uint32_t v) {
510
    SS.UndoRemember();
511
    hStyle hs = { v };
512
    Style *s = SK.style.FindByIdNoOops(hs);
513
    if(s) {
514
        SK.style.RemoveById(hs);
515
        // And it will get recreated automatically if something is still using
516
        // the style, so no need to do anything else.
517
    }
518
    SS.TW.GoToScreen(Screen::LIST_OF_STYLES);
519
    SS.GW.Invalidate();
520
}
521

522
void TextWindow::ScreenChangeStylePatternType(int link, uint32_t v) {
523
    hStyle hs = { v };
524
    Style *s = Style::Get(hs);
525
    s->stippleType = (StipplePattern)(link - 1);
526
    SS.GW.persistentDirty = true;
527
}
528

529
void TextWindow::ScreenChangeStyleMetric(int link, uint32_t v) {
530
    hStyle hs = { v };
531
    Style *s = Style::Get(hs);
532
    double val;
533
    Style::UnitsAs units;
534
    Edit meaning;
535
    int col;
536
    switch(link) {
537
        case 't':
538
            val = s->textHeight;
539
            units = s->textHeightAs;
540
            col = 10;
541
            meaning = Edit::STYLE_TEXT_HEIGHT;
542
            break;
543

544
        case 's':
545
            val = s->stippleScale;
546
            units = s->widthAs;
547
            col = 17;
548
            meaning = Edit::STYLE_STIPPLE_PERIOD;
549
            break;
550

551
        case 'w':
552
        case 'W':
553
            val = s->width;
554
            units = s->widthAs;
555
            col = 9;
556
            meaning = Edit::STYLE_WIDTH;
557
            break;
558

559
        default: ssassert(false, "Unexpected link");
560
    }
561

562
    std::string edit_value;
563
    if(units == Style::UnitsAs::PIXELS) {
564
        edit_value = ssprintf("%.2f", val);
565
    } else {
566
        edit_value = SS.MmToString(val, true);
567
    }
568
    SS.TW.ShowEditControl(col, edit_value);
569
    SS.TW.edit.style = hs;
570
    SS.TW.edit.meaning = meaning;
571
}
572

573
void TextWindow::ScreenChangeStyleTextAngle(int link, uint32_t v) {
574
    hStyle hs = { v };
575
    Style *s = Style::Get(hs);
576
    SS.TW.ShowEditControl(9, ssprintf("%.2f", s->textAngle));
577
    SS.TW.edit.style = hs;
578
    SS.TW.edit.meaning = Edit::STYLE_TEXT_ANGLE;
579
}
580

581
void TextWindow::ScreenChangeStyleColor(int link, uint32_t v) {
582
    hStyle hs = { v };
583
    Style *s = Style::Get(hs);
584
    // Same function used for stroke and fill colors
585
    Edit em;
586
    RgbaColor rgb;
587
    if(link == 's') {
588
        em = Edit::STYLE_COLOR;
589
        rgb = s->color;
590
    } else if(link == 'f') {
591
        em = Edit::STYLE_FILL_COLOR;
592
        rgb = s->fillColor;
593
    } else ssassert(false, "Unexpected link");
594
    SS.TW.ShowEditControlWithColorPicker(13, rgb);
595
    SS.TW.edit.style = hs;
596
    SS.TW.edit.meaning = em;
597
}
598

599
void TextWindow::ScreenChangeStyleYesNo(int link, uint32_t v) {
600
    SS.UndoRemember();
601
    hStyle hs = { v };
602
    Style *s = Style::Get(hs);
603
    switch(link) {
604
        // Units for the width
605
        case 'w':
606
            if(s->widthAs != Style::UnitsAs::MM) {
607
                s->widthAs = Style::UnitsAs::MM;
608
                s->width /= SS.GW.scale;
609
                s->stippleScale /= SS.GW.scale;
610
            }
611
            break;
612
        case 'W':
613
            if(s->widthAs != Style::UnitsAs::PIXELS) {
614
                s->widthAs = Style::UnitsAs::PIXELS;
615
                s->width *= SS.GW.scale;
616
                s->stippleScale *= SS.GW.scale;
617
            }
618
            break;
619

620
        // Units for the height
621
        case 'g':
622
            if(s->textHeightAs != Style::UnitsAs::MM) {
623
                s->textHeightAs = Style::UnitsAs::MM;
624
                s->textHeight /= SS.GW.scale;
625
            }
626
            break;
627

628
        case 'G':
629
            if(s->textHeightAs != Style::UnitsAs::PIXELS) {
630
                s->textHeightAs = Style::UnitsAs::PIXELS;
631
                s->textHeight *= SS.GW.scale;
632
            }
633
            break;
634

635
        case 'e':
636
            s->exportable = !(s->exportable);
637
            break;
638

639
        case 'v':
640
            s->visible = !(s->visible);
641
            break;
642

643
        case 'f':
644
            s->filled = !(s->filled);
645
            break;
646

647
        // Horizontal text alignment
648
        case 'L':
649
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin |  (uint32_t)Style::TextOrigin::LEFT);
650
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::RIGHT);
651
            break;
652
        case 'H':
653
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::LEFT);
654
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::RIGHT);
655
            break;
656
        case 'R':
657
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::LEFT);
658
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin |  (uint32_t)Style::TextOrigin::RIGHT);
659
            break;
660

661
        // Vertical text alignment
662
        case 'B':
663
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin |  (uint32_t)Style::TextOrigin::BOT);
664
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::TOP);
665
            break;
666
        case 'V':
667
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::BOT);
668
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::TOP);
669
            break;
670
        case 'T':
671
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin & ~(uint32_t)Style::TextOrigin::BOT);
672
            s->textOrigin = (Style::TextOrigin)((uint32_t)s->textOrigin |  (uint32_t)Style::TextOrigin::TOP);
673
            break;
674
    }
675
    SS.GW.Invalidate(/*clearPersistent=*/true);
676
}
677

678
bool TextWindow::EditControlDoneForStyles(const std::string &str) {
679
    Style *s;
680
    switch(edit.meaning) {
681
        case Edit::STYLE_STIPPLE_PERIOD:
682
        case Edit::STYLE_TEXT_HEIGHT:
683
        case Edit::STYLE_WIDTH: {
684
            SS.UndoRemember();
685
            s = Style::Get(edit.style);
686

687
            double v;
688
            Style::UnitsAs units = (edit.meaning == Edit::STYLE_TEXT_HEIGHT) ?
689
                            s->textHeightAs : s->widthAs;
690
            if(units == Style::UnitsAs::MM) {
691
                v = SS.StringToMm(str);
692
            } else {
693
                v = atof(str.c_str());
694
            }
695
            v = max(0.0, v);
696
            if(edit.meaning == Edit::STYLE_TEXT_HEIGHT) {
697
                s->textHeight = v;
698
            } else if(edit.meaning == Edit::STYLE_STIPPLE_PERIOD) {
699
                s->stippleScale = v;
700
            } else {
701
                s->width = v;
702
            }
703
            break;
704
        }
705
        case Edit::STYLE_TEXT_ANGLE:
706
            SS.UndoRemember();
707
            s = Style::Get(edit.style);
708
            s->textAngle = WRAP_SYMMETRIC(atof(str.c_str()), 360);
709
            break;
710

711
        case Edit::BACKGROUND_COLOR:
712
        case Edit::STYLE_FILL_COLOR:
713
        case Edit::STYLE_COLOR: {
714
            Vector rgb;
715
            if(sscanf(str.c_str(), "%lf, %lf, %lf", &rgb.x, &rgb.y, &rgb.z)==3) {
716
                rgb = rgb.ClampWithin(0, 1);
717
                if(edit.meaning == Edit::STYLE_COLOR) {
718
                    SS.UndoRemember();
719
                    s = Style::Get(edit.style);
720
                    s->color = RGBf(rgb.x, rgb.y, rgb.z);
721
                } else if(edit.meaning == Edit::STYLE_FILL_COLOR) {
722
                    SS.UndoRemember();
723
                    s = Style::Get(edit.style);
724
                    s->fillColor = RGBf(rgb.x, rgb.y, rgb.z);
725
                } else {
726
                    SS.backgroundColor = RGBf(rgb.x, rgb.y, rgb.z);
727
                }
728
            } else {
729
                Error(_("Bad format: specify color as r, g, b"));
730
            }
731
            break;
732
        }
733
        case Edit::STYLE_NAME:
734
            if(str.empty()) {
735
                Error(_("Style name cannot be empty"));
736
            } else {
737
                SS.UndoRemember();
738
                s = Style::Get(edit.style);
739
                s->name = str;
740
            }
741
            break;
742

743
        default: return false;
744
    }
745
    SS.GW.persistentDirty = true;
746
    return true;
747
}
748

749
void TextWindow::ShowStyleInfo() {
750
    Printf(true, "%Fl%f%Ll(back to list of styles)%E", &ScreenShowListOfStyles);
751

752
    Style *s = Style::Get(shown.style);
753

754
    if(s->h.v < Style::FIRST_CUSTOM) {
755
        Printf(true, "%FtSTYLE  %E%s ", s->DescriptionString().c_str());
756
    } else {
757
        Printf(true, "%FtSTYLE  %E%s "
758
                     "[%Fl%Ll%D%frename%E/%Fl%Ll%D%fdel%E]",
759
            s->DescriptionString().c_str(),
760
            s->h.v, &ScreenChangeStyleName,
761
            s->h.v, &ScreenDeleteStyle);
762
    }
763
    Printf(true, "%Ft line stroke style%E");
764
    Printf(false, "%Ba   %Ftcolor %E%Bz  %Ba (%@, %@, %@) %D%f%Ls%Fl[change]%E",
765
        &s->color,
766
        s->color.redF(), s->color.greenF(), s->color.blueF(),
767
        s->h.v, ScreenChangeStyleColor);
768

769
    // The line width, and its units
770
    if(s->widthAs == Style::UnitsAs::PIXELS) {
771
        Printf(false, "   %Ftwidth%E %@ %D%f%Lp%Fl[change]%E",
772
            s->width,
773
            s->h.v, &ScreenChangeStyleMetric,
774
            (s->h.v < Style::FIRST_CUSTOM) ? 'w' : 'W');
775
    } else {
776
        Printf(false, "   %Ftwidth%E %s %D%f%Lp%Fl[change]%E",
777
            SS.MmToString(s->width).c_str(),
778
            s->h.v, &ScreenChangeStyleMetric,
779
            (s->h.v < Style::FIRST_CUSTOM) ? 'w' : 'W');
780
    }
781

782
    if(s->widthAs == Style::UnitsAs::PIXELS) {
783
        Printf(false, "%Ba   %Ftstipple width%E %@ %D%f%Lp%Fl[change]%E",
784
            s->stippleScale,
785
            s->h.v, &ScreenChangeStyleMetric, 's');
786
    } else {
787
        Printf(false, "%Ba   %Ftstipple width%E %s %D%f%Lp%Fl[change]%E",
788
            SS.MmToString(s->stippleScale).c_str(),
789
            s->h.v, &ScreenChangeStyleMetric, 's');
790
    }
791

792
    bool widthpx = (s->widthAs == Style::UnitsAs::PIXELS);
793
    if(s->h.v < Style::FIRST_CUSTOM) {
794
        Printf(false,"   %Ftin units of %Fdpixels%E");
795
    } else {
796
        Printf(false,"%Ba   %Ftin units of  %Fd"
797
                            "%D%f%LW%s pixels%E  "
798
                            "%D%f%Lw%s %s",
799
            s->h.v, &ScreenChangeStyleYesNo,
800
            widthpx ? RADIO_TRUE : RADIO_FALSE,
801
            s->h.v, &ScreenChangeStyleYesNo,
802
            !widthpx ? RADIO_TRUE : RADIO_FALSE,
803
            SS.UnitName());
804
    }
805

806
    Printf(false,"%Ba   %Ftstipple type:%E");
807

808
    const size_t patternCount = (size_t)StipplePattern::LAST + 1;
809
    const char *patternsSource[patternCount] = {
810
        "___________",
811
        "-  -  -  - ",
812
        "- - - - - -",
813
        "__ __ __ __",
814
        "-.-.-.-.-.-",
815
        "..-..-..-..",
816
        "...........",
817
        "~~~~~~~~~~~",
818
        "__~__~__~__"
819
    };
820
    std::string patterns[patternCount];
821

822
    for(uint32_t i = 0; i <= (uint32_t)StipplePattern::LAST; i++) {
823
        const char *str = patternsSource[i];
824
        do {
825
            switch(*str) {
826
                case ' ': patterns[i] += " "; break;
827
                case '.': patterns[i] += "\xEE\x80\x84"; break;
828
                case '_': patterns[i] += "\xEE\x80\x85"; break;
829
                case '-': patterns[i] += "\xEE\x80\x86"; break;
830
                case '~': patterns[i] += "\xEE\x80\x87"; break;
831
                default: ssassert(false, "Unexpected stipple pattern element");
832
            }
833
        } while(*(++str));
834
    }
835

836
    for(uint32_t i = 0; i <= (uint32_t)StipplePattern::LAST; i++) {
837
        const char *radio = s->stippleType == (StipplePattern)i ? RADIO_TRUE : RADIO_FALSE;
838
        Printf(false, "%Bp     %D%f%Lp%s %s%E",
839
            (i % 2 == 0) ? 'd' : 'a',
840
            s->h.v, &ScreenChangeStylePatternType,
841
            i + 1, radio, patterns[i].c_str());
842
    }
843

844
    if(s->h.v >= Style::FIRST_CUSTOM) {
845
        // The fill color, and whether contours are filled
846

847
        Printf(false, "");
848
        Printf(false, "%Ft contour fill style%E");
849
        Printf(false,
850
            "%Ba   %Ftcolor %E%Bz  %Ba (%@, %@, %@) %D%f%Lf%Fl[change]%E",
851
            &s->fillColor,
852
            s->fillColor.redF(), s->fillColor.greenF(), s->fillColor.blueF(),
853
            s->h.v, ScreenChangeStyleColor);
854

855
        Printf(false, "%Bd   %D%f%Lf%s  contours are filled%E",
856
            s->h.v, &ScreenChangeStyleYesNo,
857
            s->filled ? CHECK_TRUE : CHECK_FALSE);
858
    }
859

860
    // The text height, and its units
861
    Printf(false, "");
862
    Printf(false, "%Ft text style%E");
863

864
    if(s->textHeightAs == Style::UnitsAs::PIXELS) {
865
        Printf(false, "%Ba   %Ftheight %E%@ %D%f%Lt%Fl%s%E",
866
            s->textHeight,
867
            s->h.v, &ScreenChangeStyleMetric,
868
            "[change]");
869
    } else {
870
        Printf(false, "%Ba   %Ftheight %E%s %D%f%Lt%Fl%s%E",
871
            SS.MmToString(s->textHeight).c_str(),
872
            s->h.v, &ScreenChangeStyleMetric,
873
            "[change]");
874
    }
875

876
    bool textHeightpx = (s->textHeightAs == Style::UnitsAs::PIXELS);
877
    if(s->h.v < Style::FIRST_CUSTOM) {
878
        Printf(false,"%Bd   %Ftin units of %Fdpixels");
879
    } else {
880
        Printf(false,"%Bd   %Ftin units of  %Fd"
881
                            "%D%f%LG%s pixels%E  "
882
                            "%D%f%Lg%s %s",
883
            s->h.v, &ScreenChangeStyleYesNo,
884
            textHeightpx ? RADIO_TRUE : RADIO_FALSE,
885
            s->h.v, &ScreenChangeStyleYesNo,
886
            !textHeightpx ? RADIO_TRUE : RADIO_FALSE,
887
            SS.UnitName());
888
    }
889

890
    if(s->h.v >= Style::FIRST_CUSTOM) {
891
        Printf(false, "%Ba   %Ftangle %E%@ %D%f%Ll%Fl[change]%E",
892
            s->textAngle,
893
            s->h.v, &ScreenChangeStyleTextAngle);
894

895
        Printf(false, "");
896
        Printf(false, "%Ft text comment alignment%E");
897
        bool neither;
898
        neither = !((uint32_t)s->textOrigin & ((uint32_t)Style::TextOrigin::LEFT | (uint32_t)Style::TextOrigin::RIGHT));
899
        Printf(false, "%Ba   "
900
                      "%D%f%LL%s left%E    "
901
                      "%D%f%LH%s center%E  "
902
                      "%D%f%LR%s right%E  ",
903
            s->h.v, &ScreenChangeStyleYesNo,
904
            ((uint32_t)s->textOrigin & (uint32_t)Style::TextOrigin::LEFT) ? RADIO_TRUE : RADIO_FALSE,
905
            s->h.v, &ScreenChangeStyleYesNo,
906
            neither ? RADIO_TRUE : RADIO_FALSE,
907
            s->h.v, &ScreenChangeStyleYesNo,
908
            ((uint32_t)s->textOrigin & (uint32_t)Style::TextOrigin::RIGHT) ? RADIO_TRUE : RADIO_FALSE);
909

910
        neither = !((uint32_t)s->textOrigin & ((uint32_t)Style::TextOrigin::BOT | (uint32_t)Style::TextOrigin::TOP));
911
        Printf(false, "%Bd   "
912
                      "%D%f%LB%s bottom%E  "
913
                      "%D%f%LV%s center%E  "
914
                      "%D%f%LT%s top%E  ",
915
            s->h.v, &ScreenChangeStyleYesNo,
916
            ((uint32_t)s->textOrigin & (uint32_t)Style::TextOrigin::BOT) ? RADIO_TRUE : RADIO_FALSE,
917
            s->h.v, &ScreenChangeStyleYesNo,
918
            neither ? RADIO_TRUE : RADIO_FALSE,
919
            s->h.v, &ScreenChangeStyleYesNo,
920
            ((uint32_t)s->textOrigin & (uint32_t)Style::TextOrigin::TOP) ? RADIO_TRUE : RADIO_FALSE);
921
    }
922

923
    Printf(false, "");
924

925
    if(s->h.v >= Style::FIRST_CUSTOM) {
926
        Printf(false, "  %Fd%D%f%Lv%s  show these objects on screen%E",
927
                s->h.v, &ScreenChangeStyleYesNo,
928
                s->visible ? CHECK_TRUE : CHECK_FALSE);
929
    }
930

931
    Printf(false, "  %Fd%D%f%Le%s  export these objects%E",
932
            s->h.v, &ScreenChangeStyleYesNo,
933
            s->exportable ? CHECK_TRUE : CHECK_FALSE);
934

935
    if(s->h.v >= Style::FIRST_CUSTOM) {
936
        Printf(false, "");
937
        Printf(false, "To assign lines or curves to this style,");
938
        Printf(false, "right-click them on the drawing.");
939
    }
940
}
941

942
void TextWindow::ScreenAssignSelectionToStyle(int link, uint32_t v) {
943
    Style::AssignSelectionToStyle(v);
944
}
945

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.