Suggestion for styling

@Simeon @John - just playing with a project and changing styles for text etc when the thought occurred to me that it would be an advantage if you could create and name a style in setup and call it In draw.

Like


title = “project name”
Texting = (
        fill(255, 5, 0),
        font("Baskerville-BoldItalic"),
        fontSize(64),
        textMode(CENTER)
       )

Then use it like:


function draw()
    background(113, 206, 155)
    pushStyle(Texting)
        text(title, WIDTH/2,HEIGHT/2)
    popStyle()
end

That could make the code less bulky and more modular.

@Bri_G Couldn’t the info be put in a function and just call the function.

@dave1707 - yeah but I don’t know what the overheads of using a function are and just thought why not use the parentheses with a variable call. Could add a style definition with new command calls setStyle() or defStyle() like

redText = defStyle(blah,blah,blah,….)

Could also use them in conditional statements then like

if up == true then pushStyle(blue) else pushStyle(green) end

Just an idea to make styling slicker and code listing easier to digest.

Hey @Bri_G, I’m considering something like this for Codea 4

There are a number of changes being considered to streamline the API in general

-- fluent syntax, allowing multiple style calls per line
style.push().fill(color.white).stroke(color.red).strokeWidth(5)
local savedStyle = style.get()
style.pop()

-- reset to the default style
style.reset()

-- re-use the saved style
style.push(savedStyle)

-- create a style from a table, which you can use later
local styleFromTable = 
style 
{
  fill = color(255),
  strokeWidth = 5,
  blendMode = blend.additive
}

This gives you a great deal of flexibility when using and reusing styles, what do you guys think?

@John - looks fine, gives us more options with less general congestion. Is there any way to simulate this in Codea as is now? Give us a chance to check out the options.

It does seem to me fairly trivial to set this up yourself as a wrapper on pushStyle() and popStyle().

I have actually done this exact thing myself in some projects.

Of course it would be more convenient to have it as part of the API, I totally agree.

Just saying that if you really need this right now it’s not hard to do.

And fwiw, I think pushStyle() and popStyle() are also function calls, aren’t they? :slight_smile:

@UberGoober - can you post up an example, save me time in building my own.

@John - Love2D assigns the rect, ellipse and text modes within the respective calls (if I remember correctly) that would simplify the options.

function calls are fast in Lua. Since all the fill() etc are functions, embedding the batch in a function will add only some small fraction over putting it in line, that is, it’s roughly as if you added one more style element.

@John I am personally not a super fan of the fluent syntax approach, as, due to my ancient experience, it’s never clear to me how it actually works, so you sort of have to do it by rote. However, it’s popular and once learned, maybe a bit nicer. Though I don’t see today’s approach as much worse than your example, since I can write:

pushStyle();fill(color.white);stroke(color.red);strokeWidth(5)

That’s pretty much what we’d have to say today, not much difference at all.

The style.xxx() syntax does reduce name-space pollution, which is a good thing, at the cost of one more dictionary fetch. Probably a worthy tradeoff, and Lua seems to be moving in that direction in general.

I know we’re all wondering about Codea 4 and how many months or years away it may be. Do try to avoid second-system syndrome, please.

Thanks,

R

I used this in my original DoubleChoose project (soon to be updated :slight_smile: ):


StyleTable = class()

--[[
A StyleTable can preserve the current style settings and restore them when requested.
]]

function StyleTable:init()
    --create an empty style table
    self.style = {}
    --initialize with whatever the current style values are
    self:captureCurrentStyle()
end

function StyleTable:apply()
    --go through all the style table's keys and values
    for key, value in pairs(self.style) do
        --use a key as a command for setting its value
        _G[key](unpack(value))
    end
end

function StyleTable:captureCurrentStyle()
    --store all the current style settings
    self.style.stroke = {stroke()}
    self.style.strokeWidth = {strokeWidth()}
    self.style.fill = {fill()}
    self.style.font = {font()}
    self.style.fontSize = {fontSize()}
    self.style.textWrapWidth = {textWrapWidth()}
    self.style.textAlign = {textAlign()}
    self.style.textMode = {textMode()}
    --(you can manually set any variable to nil to prevent it from being changed when apply() is called)
end

This works more like an object than a direct wrapper on the style() calls.

You’d use it like this:


pushStyle()

 - -set style how you want it

sTable = StyleTable() - - automatically captures the current style when initialized

popStyle()

- - apply the stored style later:

sTable:apply()

…this isn’t exactly what you’re looking for but I think it demonstrates the principles at play.

I think one could probably exactly implement @John 's style.xxx() pretty readily, directly in Lua. I’ll put it on my list to try …

@UberGoober - that’s exactly what I had in mind. Class() lends itself to my view as it provides the setup definition block and a draw() function which simplifies the main draw() function. I had in mind one for each call text, rect and ellipse.

Thanks for posting that.

@John what is your plan, in the fluent form, for getting the current value back?

style.stroke()

could return it, but that breaks the fluidity (and must). I imagine one could return two values, style and the result, or one could have style.getStroke().

Have you formulated a plan? I ask because I’m implementing it just for fun.

I tried building a fluent interface like the one that @John proposes. As things stand, I found it less than compelling. John’s scheme will reduce namespace pollution, but I’m not sure it really makes the programmer’s life much better, if at all.

See what you think.

I find the dismissive-sounding comment “other than reducing namespace pollution” a bit mystifying—isn’t that a pretty big benefit all on its own?

For me this change would make it tons easier to decipher other peoples code, because instead of scanning through a list of individual style commands, looking for where the actual code is, I can see at a glance where the style information is and where the code that’s doing something is.

I like it a lot.

i think it’s a trade off. it reduces a few global names, and requires the developer to type style.stroke(...) instead of just stroke(...).

typing

style.stroke(...).strokeWidth(...).rectMode(...)

is surely less readable than

stroke(...)
strokeWidth(...)
rectMode(...)

I don’t see that it has high net value, and am not entirely convinced it has positive value at all.

i think your class has a better chance of being valuable.

All - OK guys, playing with this idea ran into a problem - anyone any idea how to pass a font specified for text() to a function?

I don’t see any reason both systems couldn’t be used side-by-side, for that matter, but if both systems were available I feel pretty darn sure I’d use this one every time.

@Bri_G are you trying to re-use a StyleTable object but replace the font?

@UberGoober - all I’m trying to do is pass the fontID onto a function so that I can get the function to print text in that font.

@RonJeffries I think you and I may have fundamentally different perspectives on the value of small benefits.

It seems like what is of most value to you is something that can hugely reduce the complexity of a task, whereas I am much more interested in shaving milliseconds off of tasks I do over and over and over.

For example, when I first learned Lua I fell head-over-heels in love for the simple reason that it doesn’t use semicolons. It was the first language I’d come across that didn’t use semicolons. (Yes, this was a while ago)

To my way of thinking, the sheer number of hours of life wasted on both typing semicolons and hunting down semicolon-related bugs is probably the equivalent of thousands if not millions of entire human lives, and it just thrilled me to imagine that could be a thing of the past.