For the SDT tool in PCB mode we allow users to create pads not only with the
mouse, but also by entering the data in form of a string, which is some form of
a batch mode. A PCB pad is basically a rectangle, with an attached number and a
name. The text input string has this shape:
Pad x1, y1, +x2, +y2, Radius, dx, dy, N, Number, Name
First parameter "Pad" is an optional string with default value "Pad"
x1, y2 are floats in string form, same x2 and y2. But x2 and y2 can be prefixed
with a "+" indicating that x2 and x2 is not the opposite corner of the pad but
width and height. Radius is an optional float parameter with default value
zero. dx, dy are optional float numbers with default zero, the describe the
translation if we have to create not only one single pad, but multiple. N is an
optional non negative integer which tells how many pads should be created.
Finally Number and Name are plain optional strings.
Unfortunately it gets more complicated by the fact that the values do not have
to be separated by comma , but semicolon or arbitrary whitespace should be also
allowed. Example input:
Pad 100, 100 120.5;140.5 7.5 100 0 8 0 PAD
I tried using parseutils, but with that the proc fills the whole screen.
strscan may work when the values are all just separated by one separator
character, but with comma or semicolon and arbitrary whitespace it is difficult.
So use PEGS or RegEx? Or preprocess the string to something like
Pad,100,100,120.5,140.5,7.5,100,0,8,0,PAD
first, and then use strscan?
Of course we could use 10 different input fields in the GUI instead. Toy
program may do it that way. But for a real application 10 input fields waste to
much space and entering all that data into one entry field is faster and
simpler -- generally user will separate data by space.
I have a similar simpler proc for entering size of the drawing area, and that
one is already ugly:
proc worldActivate(entry: Entry; pda: PDA) =
var
d: array[4, float] = [NaN, NaN, NaN, NaN]
s: array[4, bool]
t = entry.text
i, j, k: int
f: float
i = 1
entry.setIconFromIconName(EntryIconPosition.secondary, nil)
for c in mitems(t):
if c in {';', ','}:
inc(i)
c = ' '
if c in {'0' .. '9'}:
i = 0
if i > 1:
entry.setIconFromIconName(EntryIconPosition.secondary, "dialog-error")
return
while k < d.len:
i = t.skipWhitespace(j)
j += i
if j == t.len:
break
s[k] = t[j] == '+'
i = t.parseFloat(f, j)
j += i
if i > 0:
d[k] = f
inc(k)
if k == 1:
d[1] = d[0]
elif k == 3:
d[3] = d[2]
s[3] = s[2]
case k
of 0:
d = DefaultWorldRange
of 1, 2:
d[3] = d[1]
d[2] = d[0]
d[0] = 0
d[1] = 0
of 3, 4:
if not s[2]:
d[2] -= d[0]
if not s[3]:
d[3] -= d[1]
else:
discard
t.setLen(0)
for f in d:
t.add(fmt("{f:g}, "))
t.setlen(t.len - 2)
entry.setText(t)
(pda.dataX, pda.dataY, pda.dataWidth, pda.dataHeight) = d # (d[0], d[1],
d[2], d[3])
pda.fullScale = min(pda.darea.allocatedWidth.float / pda.dataWidth,
pda.darea.allocatedHeight.float / pda.dataHeight)
updateAdjustments(pda, 0, 0)
pda.paint
Run