Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Suggestion for styling

edited November 11 in Suggestions Posts: 2,496

@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.

Tagged:

Comments

  • dave1707dave1707 Mod
    Posts: 9,725

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

  • Posts: 2,496

    @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.

  • JohnJohn Admin Mod
    Posts: 679

    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?

  • Posts: 2,496
    @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.
  • Posts: 1,547

    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? :)

  • edited November 11 Posts: 2,496
    @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.
  • Posts: 1,275

    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

  • edited November 11 Posts: 1,547

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


    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.

  • Posts: 1,275

    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 ...

  • edited November 11 Posts: 2,496
    @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.
  • Posts: 1,275

    @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.

  • Posts: 1,275

    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.

  • Posts: 1,547

    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.

  • Posts: 1,275

    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.

  • Posts: 2,496

    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?

  • edited November 11 Posts: 1,547
    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.
  • Posts: 1,547
    @Bri_G are you trying to re-use a StyleTable object but replace the font?
  • Posts: 2,496

    @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.

  • edited November 11 Posts: 1,547
    @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.
  • Posts: 2,496
    @UberGoober - hmmm, semicolons I do miss them.

    No seriously, I remember chasing bugs which were down to missing semi-colons - and I don't miss them !!!

    But I do like discovering how systems work and just found a big hole under fonts. How does Codea assign them. Just a small cog in a massive tool that is Lua and Codea.

    I'm assuming there's a table with entries pointing to each font/font address. Is it something embedded in iOS ?
  • edited November 11 Posts: 1,547
    That’s why I love autocomplete so much—even in its limited current form I bet I use it at least three times every minute, often more. Any small improvement in autocomplete is like gold to me.
  • Posts: 2,496
    I pity your keyboard/touch-screen must be red hot.
  • Posts: 1,547

    Really? I know you’re joking but that’s really not a lot. If I tapped the quick-bar three times a minute for a thousand years I don’t think it’d ever get hotter than it started.

  • edited November 11 Posts: 1,547

    …but on the other topic, I’m confused about the obstacle you’re encountering.

    Below I’m finagling the font a bit, but the relevant part is at the end, where I’m capturing a font as a variable, changing the font, and then passing that variable to a function that uses it to change the font back.

    Results attached.


    print(font()) h = font() font("AmericanTypewriter-Bold") print(font()) atb = font() font(h) print(font()) font(atb) print(font()) function changeFont(fontName) font(fontName) end changeFont(h) print(font())
  • Posts: 1,275

    autocomplete is nice, though I am not sure the recent changes are improvements.

    as for small improvements, I'm all for them. however, since the time our masters have to spend on Codea is limited, I prefer small high value improvements. I think the style-dot thing may be an improvement, though I'm not sure. I am pretty sure it's not a high-value improvement.

    As for what saves time, I predict that if you track your programming time, you will find that typing less will not much improve your overall time to get things done. I suspect you'll find that thinking without typing, and especially debugging, are where the time sinks are.

    But maybe that's just me. If everything I typed was perfectly correct, typing time would be more important. :wink:

  • Posts: 1,547
    @RonJeffries —ah but there you go again—what you call *high value* is different than what I call high value.

    For me the recent autocomplete changes are *vast* improvements, even though the feature still only works correctly like 40% of the time.

    And autocomplete saves way more than just strict typing time—I am what you might call memory-challenged, and simply not having to scroll around or change tabs to remember a variable name is, as I say, gold.

    Autocomplete literally lets me think less, program more—so for me the thing you’re criticizing, ironically, has all the virtues you’re praising.
  • Posts: 1,275

    :) i do recommend that you track your time spent. i don't know what you'll learn, but i'm sure you'll learn something.

  • Posts: 1,547

    I’m not sure how I’d track time saved not pressing keys and not searching for variable names.

    I think I also have a pretty good internal barometer in that every time autocomplete works I’m a little pleased, and every time it doesn’t work I’m a little annoyed — and I suppose it goes without saying that I rate a low annoyance level in the high value category.

  • JohnJohn Admin Mod
    Posts: 679

    :blush: I didn't expect this topic to get so much attention

    @RonJeffries so the main rationale behind the proposed change was indeed trying to reduce namespace polution. I'm a fan of fluent syntax, but I can see it's not for everyone. I tend to do the following:

    style.push()
       .fill(255)
       .strokeWidth(5)
       .stroke(255, 255, 255, 128)
    

    There's also the possibility of just writing the style.fill(255) etc... on each new line. Any time you see a color argument you can give it a color object or any of the standard overloads (i.e. grayscale, rgb, rgba, grayscale+alpha)

    As for getting style values I just assumed you wouldn't really be trying to get multiple ones so passing zero parameters causes it to return the style value rather than the the style table/namespace. It seemed like the most sensible thing to do.

    I was trying to be consistent with this new syntax, so I've been playing with matrix.push() and context.push() as well.

    I'm also working on stuff like require 'legacy' for compatibility with older projects.

    As for timelines, I've been out of commission for the last month, which has delayed the project. Once the IDE is compatible with Codea 4 and is useable, we will immediately go into early beta and all you guys can start playing with it so we can get feedback and suggestions.

    I'm also looking into having a dedicated Library folder like Shade has for adding user extensions to Codea, that will function globally. The new class bindings also supports this, so as an example I've already done the following when playing around with the new editor:

    -- Entity class extensions
    
    function entity:placementWobble(duration, spinCount, tiltAngle, height)
        local scn = self.scene
        local y = self.y
        self.y = y + height
        scn:tween(self):to{y = y}:time(duration * 0.75):ease(tween.bounceOut):unscaled()
    
        local up = vec3(0,1,0)
        local right = vec3(1,0,0)
        scn:tween{t = 0}:to{t = 1}:time(duration):ease(tween.circularIn):unscaled():onStep(function(tween, t)
            local t2 = 1.0 - t
            local dir = quat.angleAxis(tiltAngle * t2, right) * up
            local dir2 = quat.angleAxis(t * spinCount * 360.0, up) * dir
            self.rotation = quat.fromToRotation(vec3(0,1,0), dir2.normalized)
        end)
    end
    

    Yes, the new tween system is also fluent. I can't help myself :blush:

    So if people wanted to just add new methods to existing built-in types, this will be possible. Making Codea a bit more flexible. This will also work with shaders, so you can #include something from the library, the project or even a lua function that lives in the shader and dynamically generates code.

    I know it's extremely slow going at the moment, so I hope it'll be worth it for you guys

  • JohnJohn Admin Mod
    Posts: 679

    This is what the entity:placementWobble() function was being used for:

  • edited November 12 Posts: 2,496

    @John - OMG that’s mind blowing. Please tell me that doesn’t need the latest iPad tech to run? I’m already seeing my iPad slowing down with iOS upgrades and the knock on effect with Codea.

  • JohnJohn Admin Mod
    Posts: 679

    @Bri_G what version of iOS can you run? The current build is using 14.6

  • Posts: 1,275

    Interesting stuff, John. I'm sorry to hear you've been out of commission and hope you're back up to standard now.

    I certainly have no problem with fluent syntax, other than that sometimes you're not really sure what has happened or how it works, as we see in CodeaUnit, which is mostly magical to the reader. That's the case to a lesser extent in collection handling such as we see in Python, where the syntax passes the result on, rather than the original style or whatever. I value keeping the namespace clean, even though it doesn't help me much day to day.

    I do think the "legacy" idea is a good one. I would try never to use it, but when you just need to get some old program going, it would be helpful.

    As a rule, I'd personally prefer classes for fluent syntax, as you show with tween, but I think that's a personal preference left over from my long OO career: arguably Lua is more about functions than objects. I imagine that it might be best if you could lean Codea pretty firmly in one direction or the other rather than have some this.that().mumble() sometimes and foo:bar():baz() other times.

    The library folder is very valuable. I gather that one has to include or require things, which seems like the right thing to do.

    Where I'd like to get more help in Codea usage is on the editor side. Some form of snippets capability seems like it would be valuable, though I admit I'd probably have more like 5 snippets than 50, so I can't say it would be amazingly valuable. I wish there were at least a replace that worked, and I'd simply love some real refactoring support, but in the absence of menus, controlling that would be difficult. And, of course, it's bloody hard to do real refactoring that are context sensitive.

    Anyway, Codea is amazing given the limits of the iOS system, and Apple's bizarre rules. I look forward to Codea 4 with antici ...

    pation.

    Thanks!

    R

  • Posts: 1,275

    @UberGoober of course we all get to program as we wish. As I use a magic keyboard for programming, and because it's so erratic, I'd turn off the autocomplete if I could. I think I have a lower tolerance for irritation than even you claim. :smile:

    I am quite sure that my time spend debugging ... and mind you, with my focus on TDD and testing, I don't have to debug often .. my time spent debugging is far greater than my time spent typing. So no amount of time saved typing will make up for the absence of some feature that helps me avoid common mistakes.

    And I have a few mistakes that are quite common. I often forget to return the result of some accumulation, a table build or iterative approximation. And I even forget to return results in general. Sometimes I copy-paste something and fail to make all the needed changes. Sometimes I typo a name and get a mysterious nil somewhere. I'd pay extra for an "allow no globals here" feature.

    Finding most of those mistakes is quick, since I usually run the program quite frequently, every 5 or 10 minutes at most. But sometimes I get into a long programming cycle, 20 minutes or more, and then when I finally run, something weird happens, and sometimes it's hard to find. Next thing I know, I've gone 90 minutes with nothing working, I've bashed prints all over the program, and there's nothing for it but to revert.

    Your experience might be quite different, and so the things you need that would really save you time would be different as well. I find value in paying attention to what really slows me down, so that I can develop tools and habits that help me go faster without mistakes.

    I suspect there are some common areas where "most" programmers would benefit from similar tools and habits. And I'm sure that there are plenty of programmers who work differently, perhaps better, and who wouldn't get as much benefit from the things that help me.

    If there's a general good idea here, it might just be that we do well to pay attention to what works for us, and what doesn't, and try to adjust how we work to stay in the good places more of the time.

    Everyone's mileage varies ... and we're all somewhat the same, and somewhat different.

    One example: for me, your style-saving object would be more valuable than the style.this.that stuff. I think it provides more leverage.

    Another: I guess I'd better check out what you've done with CodeaUnit, to see what I can steal and put into my version.

    Rock on!

  • dave1707dave1707 Mod
    Posts: 9,725

    As for myself, I like simplicity. I’m not sure how well I’m going to like the strung out commands separated by periods as in

    style.push().fill(color.white).stroke(color.red).strokeWidth(5) . 
    

    but then I guess it’s not that different from

        pushStyle();fill(255);stroke(255,0,0);strokeWidth(5)
    

    Over the years there have been many changes and you get used to them after awhile.

  • Posts: 1,547

    @RonJeffries well if we’re going to talk about time-saving in general, the single most massive time-saver ever, for me, by orders of magnitude on top of orders of magnitude, is what I’ve learned about TDD from watching how you do it.

    I hate to be honest about how many times I have to learn the lesson, over and over and over, that it takes barely any time at all for wading right in without test cases to become a major boondoggle that I’d have avoided by just doing the seemingly-too-simple-to-be-necessary tests up front—a lesson I still haven’t learned fully, if we’re talking real talk.

    That said, I think I don’t need a time-tracking system to be 100% certain of the massive gains between being able to type three letters and then auto-complete a variable versus having to quit a project, open another one, hunt down the right variable name, quit that project, open the first one back up, hunt down the place I had been working at in my code, and then finally type the name in—if I hadn’t forgotten it already by then, or forgotten to copy it when I was looking at it (which tbh happens not a little bit), making me do the whole thing over again.

    Everybody’s different, but whenever I’m working with dependencies, that scenario comes up at least once in almost every session—so for my particular limitations, I feel confident in the value of an autocomplete that would eliminate it.

  • Posts: 1,275

    Thank you for the kind words. I'm glad you've found TDD test cases useful. As you'll see in my articles, I often skip them ... and almost always regret it. Don't be like me.

    As for dependencies, yes, they're a pain. Switching back and forth is horrid: it's one good reason why multiple instances of Codea would be wonderful.

    I rarely use dependencies other than for CodeaUnit or Cameras. I'm hoping that the new Library capability will make them easier. As for auto-complete, it seems not to help me much. I wonder what you do differently to find it more useful.

  • Posts: 1,547

    —> to be clear, I’m talking about the value I’d get from an improved auto-complete…

  • Posts: 2,496

    @John - I’m on iPadOS 15.0 and there are all sorts of new ‘multitasking’ features been added. I think this version has been sloped towards metal support at the expense of the older kit. So, graphically interchanges aspect changes etc are slow and not slick. This shows up in Codea at times - few forum notes describing observations been posted.

  • Posts: 2,496

    All - here is a little demo, showing the effect of defined styles (here held in Class defs) on text, rectangles and ellipses. It's just a toy to demonstrate how you can reduce the clutter in the draw() function and would be better built into Codea - not necessarily as I have set it up, there are probably much better ways to do this. Anyway - have a play.

  • JohnJohn Admin Mod
    Posts: 679

    @Bri_G if you have iOS 15 then it will run on your device. It uses metal and a better rendering/shader system so it'll at least run as well if not better than the existing runtime

    Your style formatter looks interesting. What we could potentially do is let you create style objects and pass them as a first argument to the graphics commands as an optional overload that uses that style. That way you can save a bunch of styles (or even save them as json files) which could be re-used whenever. All the same old style state would still work it'd just be an additional option

    @dave1707 as I said, you can still just put one statement per line, or use the legacy versions. The intent is to clean up the API namespace to make room for future additions without clogging it all up

    @RonJeffries The inconsistency between . and : does bother me but the main reason for it is, one returns a new object (a tween) and the other is just returning the namespace. I could make it use : syntax for both, but for some reason that felt like a cludge to me...

  • dave1707dave1707 Mod
    Posts: 9,725

    @John I’ve been thru many Codea changes. I’m sure once those come out I’ll be using them. It will seem strange in the beginning, but after awhile it will be normal.

Sign In or Register to comment.