Technology Update 2021

Progress Day 18

Somehow I managed to forget the MIDI Channel Bar control and since it’s an easy one decided to knock it off. Still needs some theming work, but coding is done:

Over the years, I’ve written this control 3 or 4 times now. This time, the new GuiKit made it almost trivial - about 200 lines of code.

9 Likes

Progress Day 19

Starting Monday, my main goal is to get the timeline and wiring diagrams ported to the new GuiKit. This is going to be a bit of work so I thought I’d give myself a bit of a head start.

Similar to the way I separated the scrolling and content in the ticker view I want to do the same thing with the time line view. Again, the idea is to save duplicating the code for all those touch/drag/zoom interactions.

So to make sure GuiKit was up to the task I put together a simple test program to experiment with all the geometry calculations. It looks a mess, but does the job:

To explain what’s going on there:

  • The time line is split into three main areas, from top to bottom: the time axis (dark gray), the content area (black area) and the scrollbar
  • The scrollbar, the time axis and the content area all need to have their geometry synced - which is confirmed with the numbers displayed in each (content offset 173.5…, content size 992.85).
  • The crossed out blue box is just there so I can see something happen when I zoom/scroll and make sure it’s in the correct place and size.

Unlike other views, when you zoom in the timeline things like fonts don’t get bigger, you just zoom in on the data - so in this case, zooming works by adjusting the content size, not the content scale factor. GuiKit didn’t handle this before, but it does now and all the touch, scroll and zoom interactions appear to be working correctly (and this time I actually tested it on a real touch screen device to be sure).

8 Likes

Progress Night 19

Last night I did some experimenting with vector graphics for the new theming engine in GuiKit…

First some background… GuiKit’s theming uses a concept of “drawables”. Drawables are anything that can be used to fill a region of the screen. eg: a button control has a background drawable that controls how the background area of a button is drawn.

Currently GuiKit supports these drawables:

  • Solid Color
  • Gradient Fill (horizontal or vertical)
  • Raster Image (ie: aka png)
  • Nine Slice Raster Image
  • Selector (which selects a drawable based on the control state, eg: pressed, checked, normal etc…)

As you can see the two image drawables are based on raster images. This works, but there are cases where vector assets would be a better choice - either for performance, size or maintainability reasons.

So last night I started adding some vector drawables:

  • Border - filled area with colored border on selectable edges
  • Ellipse - ellipses and circles
  • Rectangle - with optional rounded corners
  • Path - svg style path data shapes

Also, some new utility drawables:

  • Composite - combines multiple drawables into one (will probably rename to group)
  • Padded - adds padding space around another drawable and optional positioning within it (need a better name for this one).

Of these, the Path drawable is the most interesting because it uses SVG path data to draw shapes. eg: here’s path drawable using the shape data from Cantabile’s panic button:

I need to think carefully about how I use this because depending on the content, vectors can be either faster, or much much slower to render.

But I’ll come back to this tonight.

3 Likes

Very cool Brad!!

Progress Day 20

Made some good progress today starting with finishing off the theming of the MIDI Channel Bar that I didn’t get to on the weekend:

Then it was on to the timeline view. I’m taking a different approach with this one… instead of rewriting it (like the ticker view) or just porting it (all the others), this time I’m pulling it apart and putting it back together piece by piece using bits of the original codebase combined with the improved parts of GuiKit.

So far I’ve got the time axis and position markers appearing and all the scrolling and zooming is working. (The long string of numbers are the remnants of my weekend experiments - they’ll be gone soon).

This is a complicated control this one… it’s probably going to take a few days.

4 Likes

4 posts were split to a new topic: Select multiple channels for MIDI routing

Progress Night 20

More experimenting with vector artwork in GuiKit. Everything in the following video was authored in GTL (GuiKit’s Theming Language) without any references to external images.

GTL Vector Art Experiments

(To be clear, this is not GTL support for SVG… rather it just lets you copy path data from path nodes in a SVG file to create the shape outlines).

4 Likes

Progress Day 21

More progress on the timeline:

  • Focus management of selected marker/content view
  • Keyboard interaction to scroll and move markers (including fine and coarse mode)
  • Dragging of play position and range markers (including snap/no-snap)
  • Properties for all the marker positions and view ranges
  • Notifications when scroll, move marker, play position etc…
  • Zoom In/Out/ToMarkers/ToPlayPosition
  • Content renderer wired up. (I won’t be hooking up real MIDI/audio data in this view yet because I need the audio engine for that… so I’ve just plugged a content renderer that draws a big X)

Still lots of fiddly things to sort out:

  • Test Labels
  • Label hit testing and selection
  • Stretch view range when view resized?
  • Auto-scroll when current position moved programmatically
  • Larger hit area for handles on touch screens
  • Clicking a label should move current position
  • Suppress dangerous click when giving focus
  • Cursor highlight
  • Z + click and drag to zoom
  • Alt + click and drag to set play range
  • Only fire range marker changed on drag release
  • Maintain range marker order and update play position
  • Test with null timescale
  • Overscroll past end
  • Testing, testing, testing…

I’m hoping to get most, if not all of that knocked off tomorrow.

9 Likes

Progress Day 22

Timeline view finished. Nothing new to show because it looks the same as yesterday, but everything on the todo list in the previous post is done.

Nice bonus… even though I’ve added a bunch of XML doc comments, the code for the new timeline is only 80% of the size (by line count) of the old one - primarily because I’m leveraging cool stuff in the new GuiKit.

Tomorrow I’ll give it some more testing and final tidy up of the code before moving on to the last GUI control - the wiring view.

10 Likes

Progress Day 23

Today I started on the Wiring View. This is another fairly complicated control but since it was developed after the original version of GuiKit’s ScrollView class I don’t need to tease out the scrolling code this time.

Porting requires addressing two major areas:

  1. Converting its theme to GTL.
  2. Reworking the mouse/touch interactions

Today’s job was the theming which involved converting this wall of code:

to this nicely structured GTL and updating the wiring view to use it - which it now does:

Tomorrow’s I’ll be converting a gigantic 600 line function that does all the mouse/touch click and drag interactions into a series of clean GuiKit gesture handlers.

5 Likes

I’ve become used to the table view but at the beginning I remember losing quite some time troubleshooting some copied/pasted blocks and was unaware of multiple routes from same source to the same plugin. This info is clearly evident in table view but gets lost in diagram view. Is some improvement planned here?
Regards,
Matej

1 Like

Hi @matejb,

Right now I’m just aiming to match the existing functionality but I was thinking about how to address this problem and one thought was to simply offset the wires so you can there are multiple, something like this:

No promises, but would that help?

Brad

3 Likes

Hi Brad, it would sure very much help. Personally I now actually prefer the table view as it provides much more functionality and metering, but for those who prefer the simple diagram view your offset suggestion would solve and eliminate trouble I had at the beginning.
Thanks and regards,
Matej

1 Like

Hi Brad, Great work! Have you given any thought to making the psuedo-presets list dynamic? Kind of like the set lists or states.

Thanks,
John

Hi @Jtoth,

I have, but not as this part of this batch of work. I’ve logged it here for now.

Progress Day 24

When I originally wrote the WiringView I was on a time push to get it done. I remember thinking at the time that I should separate out the different UI interactions but laziness won and I left it as a bit of a mess.

So today was the tedious job of separating out all those UI interactions. That’s now done and everything is working again.

Technical side note for the devs: One thing I’ve found that’s been working really well in this work is using closures to maintain the state. For example this is the code that handles the “click’n’drag box selection” action:

Previously I would have implemented this with either a separate nested class or a bunch of member variables to maintain the state. Instead I’m now using closures to encapsulate everything to do with this action into a single function. The WiringView’s entire UI interaction model is now is just a bunch of functions like this:

(end side note)

Now that the WiringView is done, the porting of Cantabile.Gui is complete and I’ve got a nice collection of cleaned up, refactored, ported, documented controls ready to go.

I’m probably going to take a couple of days break now since I’ve been at this for over 3 weeks straight. After that these posts will become more sporadic as the next task is a bit of a black box and I won’t have much to show until it’s done.

10 Likes

Well done - have a coffee and a bun! :+1:

2 Likes

Thanks! (But I’m thinking more along the lines of Bourbon and snacks. :slight_smile:)

6 Likes

Have a “Steam goat” beer - one of my favourite Aussie beers (along with Coopers) when I was in Melbourne. Seems like a lifetime ago, but I can still taste that Steam goat!

2 Likes

Weekend Update

Earlier in the week I mentioned working on adding vector support to GuiKit’s theming capabilities. I’ve now completed that work and converted GuiKit’s two built-in themes to exclusively use vectors (instead of pngs at multiple resolutions).

I’m really pleased with the result because:

  1. The final themes packages are much smaller…

old:

image

vs new:

image

  1. They’re now infinitely scalable with no pixelation artefacts. Full screen radio buttons anyone? Ah the crispness.

  1. They’re just as performant because the vector data is rasterized on demand. eg: note the Rasterize() call on the first line of the GTL code to make a checkbox:
var makeCheckBox = (fillColor, borderColor, checkColor) => Rasterize()
{
    Size: (13,13),
    Inner: [
        BorderFrame(fillColor, borderColor),
        Frame()
        {
            Padding: 2,
            Inner: Path()
            {
                SvgData: "M 11.091797,2.7460938 A 0.625,0.625 0 0 0 10.646484,2.921875 L 5.1484375,8.2480469 3.1035156,6.0507812 a 0.625,0.625 0 0 0 -0.8828125,-0.03125 0.625,0.625 0 0 0 -0.03125,0.8828125 l 2.4785156,2.6640626 a 0.6250625,0.6250625 0 0 0 0.8925782,0.021484 L 11.515625,3.8203125 A 0.625,0.625 0 0 0 11.53125,2.9355469 0.625,0.625 0 0 0 11.091797,2.7460938 Z",
                FillColor: checkColor,
                MaintainAspectRatio: true,
            }
        }
    ]
};
  1. They’re a little harder to setup, but much easier to maintain and re-use. eg: instead of drawing a bunch of radio button images, I can now programmatically generate them for each state:
Checked && Disabled: makeRadio(colorDisabledFill, colorDisabledBorder, colorDisabledBorder),
Disabled: makeRadio(colorDisabledFill, colorDisabledBorder, Color.Clear),
Checked && Pressed: makeRadio(colorFocus, colorFocus, Color.White),
Pressed: makeRadio(colorFocus, colorFocus, Color.Clear),
Checked && Focused: makeRadio(colorFill, colorFocus, Color.White),
Checked: makeRadio(colorFill, colorBrightBorder, Color.White),
Focused: makeRadio(colorFill, colorFocus, Color.Clear),
else: makeRadio(colorFill, colorBrightBorder, Color.Clear),
  1. The Light theme just imports the Dark theme and overrides the colors. Again, this reduces maintainance because most theme changes only need to be done in one place. This is the entire Light theme gtl file:
// GuiKit Standard Light Theme

// Start with Dark theme
import("GuiKit.Dark");

// Redefine colors...
var colorForm = #f5f5f5;
var colorText = #000000;
var colorScrollbar = #f5f5f5;
var colorScrollbarThumb = #C2C3C9;
var colorFocus = #0095fe;
var colorDisabledFill = #F5F5F5;
var colorDisabledBorder = #BBBBBB;
var colorDisabledText = #808080;
var colorFill = #FFFFFF;
var colorBorder = #AAAAAA;
var colorBrightBorder = #666666;
var colorButtonFill = #ECECF0;
var colorButtonBorder = #ACACAC;
var colorSubtleText = #333333;
var colorProgressBar = #00b200;

I even went to the trouble of reducing banding in linear gradients. It’s a subtle change, but stops my eyes bleeding:

I still need to convert Cantabile’s themes to a similar approach, but I’ll do that as a side project in parallel with on-going development - but will definitely aim to getting it finished before releasing this Tech Update.

11 Likes