Building NEW 'Classic' Controls

Organizing tasks to work on, New Features Ideas, Building LCS & LCB Libraries & Widgets, Redecorating and Modifying the IDE, Hacking / Editing Tools, Compiling the Engine from Source, etc.
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

"Classic controls" for those who don't know, are the original Engine controls that we've been using as UI elements in the IDE for ages. You CAN add new styled versions of them, I've added a Gray FilledButton control for example. The method for creating new variations on of 'classics' has been documented elsewhere in the forums here.

I wanted to make a new thread to cover a related, but slightly different topic.

As some may know the 'classics' are getting a bit rusty and have not been updated for recent versions of Mac OS (11+) and Windows 11, and so these UI controls may look slightly off compared to other apps on these systems. These classic controls appear to be some hybrid or emulation of UI components from different OS (could be customized subclass of). Some people may think the best thing would be to update them, which requires editing the C++ engine source and recompiling the engines. I mostly use the text fields, buttons and DataGrid myself but I would prefer to be able to use Widgets for most things, for several reason. One reason is that canvas draw Widgets can render identically on all the platforms, there is no guessing as to how it will appear once deployed to a different OS, even when running inside a web browser using the HTML5 Emscripten engine!

Those classic controls are rendered in such a way that is not sub-pixel/high DPI screen friendly and doesn't look as good as Widgets. Widgets are rendered by libSkia canvas drawing routines with sub-pixel precision! Widgets can ALSO use FFI (foreign Function Interface) in order to create a 'native' view port, and place a OS Native UI kit control inside it, provided that they can have eXtension Builder FFI binding strings created to use them.

You can look to the Browser Widget or other widgets that use 'Native layer' to see how widgets render 'placeholder' graphics when the IDE is in Edit mode, but renders external content (for examplt Native Button, or a Web Page from Chromium Embedded Browser) when the Engine is in 'Run' mode. So it may be possible to create a hybrid control that uses 'Native Layer' for native controls when available, but renders a reasonable look-a-like version when 'Native' is not available.

So I want to have a set of widget based controls that are equivalent to the classic controls in appearance, functionality, properties, but is either rendered by canvas drawing (non 'native layer') and/or using actual Native UI components provided by the OS. I'll use this thread to document this goal.

I spent some time this morning trying to fix the broken 'Mac Native' Widgets that were included in the IDE. Currently these do not render the place-holder graphic at all for some reason. But I'm getting the impression that It may be a bit trickier than I expected to create such a hybrid Native/Emulated Widget as I described. Still looking into it.

Some of these widgets I've collected for this goal have already been created previously but may not have been included in the IDE itself. Here's examples of widgets that were already, some already mobile OS theming options:
https://github.com/livecode/livecode/bl ... button.lcb
https://github.com/livecode/livecode/bl ... button.lcb
https://github.com/livecode/livecode/bl ... essbar.lcb
https://github.com/livecode/livecode/bl ... lector.lcb
User avatar
tperry2x
Posts: 3209
Joined: Tue Dec 21, 2021 9:10 pm
Location: Somewhere in deepest darkest Norfolk, England
Contact:

Re: Building NEW 'Classic' Controls

Post by tperry2x »

The other option of course is that we intentionally don't do any native controls. We do like godot does and have custom buttons which are intentionally orange / purple / whatever. At least this would have them all looking the same.
Kdjanz
Posts: 30
Joined: Mon Sep 13, 2021 5:02 am
Contact:

Re: Building NEW 'Classic' Controls

Post by Kdjanz »

My own opinion for the 2 cents that it is worth (since we don't have pennies any more in Canada, 2 cents is worth exactly nothing!):

<rant>
Native controls are a distraction for OXT because they are always changing and completely out of control of everyone here. You are setting yourself up on a treadmill to failure because you can never fully catch up and stay caught up. Pick a nice neutral wardrobe of UI elements that are NOT Apple OR Google OR Windows OR any other flavor of Linux and get on with making distinctive products that work for your clients and your software. OXT is not going to be the tool to create the next world changing piece of software or the chosen tool of the next Unicorn startup.

It's meant for real users who have a problem to solve and a wish to get their hands dirty. The color or shape of buttons is not going to matter for their solution, and only a small handful of people will ever see or use their code. If one particular user out of ten thousand absolutely must have a button that looks like Apple, Richmond has shown us that you can make your own that are pixel perfect to whatever your standard is. But the other 9,999 users are more concerned what the button does.

Concentrate on making OXT run on all the platforms - YES. But don't worry about whether it looks different on each one. Function trumps all in my books.

</rant>
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

tperry2x wrote: Sat Aug 10, 2024 2:47 pm The other option of course is that we intentionally don't do any native controls. We do like godot does and have custom buttons which are intentionally orange / purple / whatever. At least this would have them all looking the same.
Yes I'm starting to lean towards not bothering using any 'Native' widgets to try to use OS provided UI elements (Cocoa, WinUI, GTK, Qt, etc.), or trying to do some hybrid, just for simple controls like buttons, tabs, sliders, etc. Instead just make controls with lots of options/properties so users can style them to look any way they like, and maybe include some preset settings for macOS-style, Windows-style, Linux style, etc. Which I think is what the goal was with those widgets that I linked to above. Those aren't real 'native' controls but they do have settings for emulating native appearance on mobile iOS or Android and a few other options. Take that further and have settings for Desktop appearances, and more options for custom appliance (matching properties of the Engine's classic controls).

I spent some time on trying to fix the missing 'preview' for the macOS native widgets so they show something in edit mode, and also did some experiments this week in trying to create 'hybrid' (native OR Canvas Drawn) controls and it was a real pain. It did not feel like it was worth the trouble, particularly when I can get really close to matching 'native' look just by using the classic controls with a custom settings, and beyond that the widget canvas drawing I believe can allow for damn-near perfect OS appearance matching. The controls could still use scripting or XB FFI to retrieve info that may be needed to Appearance matching such as the host system's text highlighting color or whatever. Additional properties would mean the same controls can still be style in completey original styles not matching any existing OS.
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

Kdjanz wrote: Sat Aug 10, 2024 10:38 pm Native controls are a distraction for OXT because they are always changing and completely out of control of everyone here. You are setting yourself up on a treadmill to failure because you can never fully catch up and stay caught up. Pick a nice neutral wardrobe of UI elements that are NOT Apple OR Google OR Windows OR any other flavor of Linux and get on with making distinctive products that work for your clients and your software. OXT is not going to be the tool to create the next world changing piece of software or the chosen tool of the next Unicorn startup.
A problem you may not be aware of is macOS darkMode (and maybe dark themes on other OSes) can render certain custom drawn controls, which are non-adaptable, visually completely unreadable. Think about this: you have set a dark foreground text color on top of an OOP INHERITED light background, and then suddenly the light color background is changed to a dark color (inherited from the OS). Now you have dark colored text on a dark color background, which is visually extremely hard to read. Native controls aren't simply about appearance, they may have OS provided functionality and effects the come with them. And 'Native controls' should automatically adapt to changes in the appearance of the OS theme, unlike custom drawn look-alikes that need to be manually updated to keep up with the latest. As I see it that is the main point in having them, to NOT have to keep chasing the latest OS appearances.

I do like my own apps/stacks to typically look native and have native features, at least on macOS/Cocoa because, like I said, it's more than simply a static appearance. I don't personally have any clients or users but myself.

However, for the IDE I have also considered the option to just 'go our own way' and have defaults that are a generic style instead, but that also still include options (properties) so that IDE user can alter them to match whatever appearance they like. That's why I renamed my 'New Classic' control from 'macOSDarkmodeButton' to 'Filled Button' because its just a grey button, it doesn't adapt to user changes to the system appearance mode at all, and looks the same on any OS. I also tried to make new icons for the Tools palette that were non-OS specific on the same reasoning, unlike LC CE or OXT Lite my IDE tools palette has only a single set of icons "OXT IDE' set regardless of the platform its running on.
User avatar
tperry2x
Posts: 3209
Joined: Tue Dec 21, 2021 9:10 pm
Location: Somewhere in deepest darkest Norfolk, England
Contact:

Re: Building NEW 'Classic' Controls

Post by tperry2x »

I get that with the inherited colours, and how they are charged by the OS. The same is true for classic controls in Linux, although changing system appearance or theme while the IDE is running will cause a hard crash.

Can't other OS's draw the classic controls the same way Linux does?
I mean, Linux is drawing native controls - so can that method be utilised on MacOS and windows to also provide native controls?
micmac
Posts: 163
Joined: Mon Sep 13, 2021 9:46 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by micmac »

Just my opinion

I favor native OS controls

Mic
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

tperry2x wrote: Sun Aug 11, 2024 6:43 am I get that with the inherited colours, and how they are charged by the OS. The same is true for classic controls in Linux, although changing system appearance or theme while the IDE is running will cause a hard crash.

Can't other OS's draw the classic controls the same way Linux does?
I mean, Linux is drawing native controls - so can that method be utilised on MacOS and windows to also provide native controls?
I'm not sure but I don't think that the Linux Engine is really rendering Native GTK controls, more like it's inheriting properties from the OS (GTK). I believe it just does that differently depending on the OS, but it's inconsistent. For example Graphics controls and text fields and drop-down menus on macOS DO inherit the correct foreGround/backGround color from the OS (of course that's only if there's no properties set on the objects), but buttons, Menu buttons tab buttons etc. do not.

As you may recall I did do some experimenting with 'Native' GTK Button Widget, and it did look different from a Engine created button, for one thing GTK used a different default font for the button's label. https://openxtalk.org/forum/viewtopic.php?t=678

I didnt know about the hard crash on changing the system theme on Linux, that's not good.
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

Here's some screenshots of that button widget, and various other widgets I've collected that could be part of a widget-canvas drawn new-'classic controls' set, along with some classic controls:
Widget-OXTIDESet.png
Widget-OXTIDESet.png (49.09 KiB) Viewed 5412 times
There's color inheritance going on, you can see it auto-toggle between dark/light in a desirable way (unlike the classic control button. The Font names are hard coded in the Widget for iOS/Android/macOS Yosemite (current macOS version when the widget was created), but this could be made into editable property, along with adding more color editing and some layer effects options like drop shadows.
ButtonWidget-DarkMode-LightMode.png
ButtonWidget-DarkMode-LightMode.png (49.41 KiB) Viewed 5412 times
In Button-widget you can see there's options for Text Label OR an SVG Path Icon, there currently isn't both, that could be added in. Could add setting pixel data based icon.

There's very good examples of doing this in HH's Button Grid. In fact Hermann Hoch's Button Grid was a pretty awesome piece of work.

I also have a modified version of the Tile Widget used formerly only in the old Start Up center label blocks, renamed rather unimaginatively to 'Tile Plus' so I could experiment with it. You can install it from the OXT Extension Manager Repo (on Desktops with a working Browser Widget) in OXT DPE Dp4
User avatar
tperry2x
Posts: 3209
Joined: Tue Dec 21, 2021 9:10 pm
Location: Somewhere in deepest darkest Norfolk, England
Contact:

Re: Building NEW 'Classic' Controls

Post by tperry2x »

This is brilliant stuff. :D
How hard is it to integrate this into a 'vanilla' copy of LCC (or OXT Lite) as I'd like to change the 'classic controls' - at least on the mac version, over to this. edit: (Although, there's a very valid point around compatibility raised here)

Or.... here's something else I've been pondering the last few days.

As your OXT DPE edition is mainly MacOS orientated, would it be best to just have the DPE edition as the mac version, and perhaps I only continue with 'Lite' on Windows and Linux?
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

There's lots of good open source community widgets, there should be no compatibility issues with LC CE or OXT Lite.
I have more than this collected (not installed at the moment) but here's a sampling, all widgets.
CommunityWidgets.png
CommunityWidgets.png (960.08 KiB) Viewed 5279 times
That one with the OXT IDE Icon set displayed is a 'Palette Grid' widget, it's based on the SVG IconPicker widget used in the IDE.
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

tperry2x wrote: Tue Aug 13, 2024 8:24 pm This is brilliant stuff. :D
How hard is it to integrate this into a 'vanilla' copy of LCC (or OXT Lite) as I'd like to change the 'classic controls' - at least on the mac version, over to this. edit: (Although, there's a very valid point around compatibility raised here)

Or.... here's something else I've been pondering the last few days.

As your OXT DPE edition is mainly MacOS orientated, would it be best to just have the DPE edition as the mac version, and perhaps I only continue with 'Lite' on Windows and Linux?
I did do a quite a few Mac-specific extensions, and I do work on macOS most of the time, so understandable why you'd say that, but I do also have Win 10 / Linux installs for testing, just no time for testing.
A handful of Extensions libraries that I've built or worked on (FluidSynth, HIDAPI, HunSpell) are cross-platform wrappers. I have tried not to be too Mac-centric, all the non-native-layer widget stuff is cross platform and should render the same on every platform (assuming identical fonts are used), All the rest of the work on IDE has not been platform specific.

There's no problem adding whatever you want of it to your OXT Lite builds, but risk being branded OXT Slightly Over Weight, lol

My biggest problem is finding the time to work on making it a nice cohesive set of controls. There's some good widgets to start from already but they all need work done to make them better and consistent with each other.
FourthWorld
Posts: 442
Joined: Sat Sep 11, 2021 4:37 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by FourthWorld »

One benefit with the control rendering scheme implemented by the engine's inventor (compiled to machine code from C++ subclasses) is performance.

If you didn't use MetaCard back in the day it may be hard to appreciate how fast it was, and how much rendering performance has dropped over the years.

The current engine was never optimized for games and other things where rendering performance is crucial. It's now noticeably slower than the scriptable rich-media engine everyone has preinstalled on GUI devices, the browser, so ubiquitous it sets the baseline of expectations.

The implications of rendering speed go beyond just games, though that is a category I'd like to see become practical here once day. Rendering speed affects ALL redrawing, from card-to-card navigation to resizing windows. The time difference with a single control type may not impact much, but as more types are converted from machine code to interpreted code the difference compounds.

I can appreciate the attraction to a certain savings in development cost, but please keep in mind it's a net savings, with trade-offs. Many thousands of lines of C++ classes will need to be rewritten if there was an effort to replace controls across the board.

--

There's also a more subtle issue at play, regarding tool modes. Any control implementation should ideally render equally well regardless of the active tool.

xTalks offer a tool mode so devs can deliver a range of apps. SuperCard introduced the pointer tool, and with their vector graphics were able to include a sample app that was a pretty solid implementation, going far beyond MacDraw in features, rivaling SuperPaint. Seeing that example is among the top three influences that got me excited about what xTalks can do. I wouldn't be in this conversation today if it weren't for SampleDraw.

The pointer tool makes a great many app categories practical to deliver in an xTalk, anything that involves visual layout of objects. I've seen specialized CAD apps, postcard makers, facilities management, mind maps, org charts, and a great many other categories built in xTalks.

All of these remain possible where there is an acceptance of the tool mode as a core part of the language, included not just for IDE makers but for every user.

Somewhere after the turn of the century there was a philosophical shift with the tool property within that company, where it was no longer regarded as a useful language feature but instead treated as belonging exclusively to the IDE maintainers.

This shift is most pervasively evident in the language used to describe the tool mode property: over time it began to be referred to as Design Mode, with the browse tool becoming Run Mode.

This has created an environment where the value of the pointer tool in delivered apps has diminished, going so far as engine maintainers suggesting the most protective way to build apps is for scripters to write their own objects and code to emulate the existing pointer tool in the apps where they need layout features. If you've ever done it, you understand the work involved in such a suggestion.

In actionable terms, this philosophical shift, and the prospect of shifting back, invites us to consider two things:

1. IDE messaging can be designed in a way that doesn't need to prohibit devs from using key language feature like tool modes in their own apps, leaving the door open for a wide range of apoa that are free more cumbersome to build if key language feature must be rewritten in script.

2. If prompts IDE maintainers to consider control rendering methods that work equally well regardless of the current tool for a smoother overall user experience.

Thank you for considering this.
User avatar
tperry2x
Posts: 3209
Joined: Tue Dec 21, 2021 9:10 pm
Location: Somewhere in deepest darkest Norfolk, England
Contact:

Re: Building NEW 'Classic' Controls

Post by tperry2x »

How about another approach. Yes, machine code or C++ is a lot faster to execute than xTalk Script, but of course it's a behemoth to try and edit this engine - and I'm not sure if anyone has had success in compiling a Windows and MacOS version as of yet based on the last livecode community source code.

However, I wondered about C++ plugins. Whereby the IDE loads the C++ plugin externally and loads it into memory. Yes, there's probably a penalty with startup time in the IDE, but the benefits would be:

1. There's only one C++ file to edit, to make changes, rather than having to recompile the engine completely each time.
2. Updates are easier as you just swap out the C++ plugin
3. You retain the execution speed once the C++ plugin is loaded into memory.

This is just conjecture on my part - I'll defer to someone who's more of a C++ whiz
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

Eh, I'm not sure that's accurate comments in regards to what's actually going on.

LibSkia that draws the widget stuff, it is still C++ compiled code in engine doing the rendering (maybe not the compositing to the card layer), lib LibSkia is exposed to LCB (and can be exposed to script engine too) so it may be called from that intermediate byte code language module that wraps it with binding strings which point to internal engine symbols which then do the work (in the UI thread, not the script execution thread). The intermediation / extra syntax look-up might take a thread CPU clock cycle or two, so sure it's not as fast as machine code, but it's fine. Some render slowdowns can be avoided or mitigated with strategic programming of redresh timing, the coding plays a part in speed.

That's not to say I haven't noticed some degradation in the Engine's rendering speed over the years (try 9.6.1 vs 9.6.3 with Animated GIFs!), and I also certainly wouldn't mind using a rendering library that can do all sorts of GPU acceleration 3D models spinning around all over the place, and convex hull distortions on live video streams. But until someone has the time to try to wrap some amazing 3D modeling or game engine thing, or write an embedded xTalk interpreter into one, I'm happy to play around with libSkia's Canvas drawing and try to a new set controls that have a better shot at having a WYSIWYG appearance on every platform.

Widgets libSkia renders pretty faster even without GPU acceleration, they're better looking, and more capable for rendering a lot of 'objects' than using the equivalent amount of classic controls. I can prove that easily with a real world example. Just try using the classic controls to make a grid of Buttons 128 rows or 128 button columns and see how well the classic controls render vs drawing 128x 128 filled/stroked rectangles in a widget and see what renders faster, you'll be waiting a few seconds for the script/classic control version to appear, my widget version of the same grid renders instantly.

I was just working on a text 'field' widget based on MadPink's nice labelBox (which seems to be gone from his GitHub repos now?), It does auto-magic text wrapping. I'm making it have more exposed properties to the Property Inspector, and it can have a transparent background now.
Screen Shot 2024-08-14 at 1.05.12 PM.png
Screen Shot 2024-08-14 at 1.05.12 PM.png (256.18 KiB) Viewed 5141 times
I figured out how to get/expose the widgets text prop so you can 'set the text of widget' as you would the text of a field, or the text of an image (which I've always thought was named badly for 'image file data' that it is, but it's been in the interpreter for decades like that). Previously labelBox had used a custom named property name 'someText' which isn't as good for English-like syntax sentences.

Here's the Widget's XB source if anyone wants to play around with it:

Code: Select all

/**
Name: mouseUp
Type: message

Name: mouseDown
Type: message
**/

widget org.openxtalk.madpink.labelbox

--required metadata
metadata title is "LabelBox"
metadata author is "MadPink, Paul McClernan"
metadata version is "0.0.2"
metadata preferredSize 	is "242,130"
metadata svgicon is "M1664 512Q1664 432 1608 376 1552 320 1472 320L1408 320 1408 704 1472 704Q1552 704 1608 648 1664 592 1664 512ZM0 1280L1792 1280Q1792 1386 1717 1461 1642 1536 1536 1536L256 1536Q150 1536 75 1461 0 1386 0 1280ZM1856 512Q1856 671 1743.5 783.5 1631 896 1472 896L1408 896 1408 928Q1408 1020 1342 1086 1276 1152 1184 1152L480 1152Q388 1152 322 1086 256 1020 256 928L256 192Q256 166 275 147 294 128 320 128L1472 128Q1631 128 1743.5 240.5 1856 353 1856 512Z"

--use dependencies
use com.livecode.math
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
use com.livecode.foreign
use com.livecode.mathfoundation
use com.livecode.library.widgetutils

--list customizable properties

private variable mText as String
property Text 	   get mText           set setText
metadata Text.editor      is "com.livecode.pi.text"
metadata Text.user_visible is "true"
metadata Text.default     is "A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools.\n\n-Douglas Adams"
metadata Text.section 		is "Basic"

--metadata for built-in properties:
metadata foregroundColor.editor		is "com.livecode.pi.color"
metadata foregroundColor.default is "255,255,255,50"
metadata foregroundColor.section is "Colors"
metadata foregroundColor.label is "Text Color"

metadata backgroundColor.editor		is "com.livecode.pi.color"
metadata backgroundColor.default is "140,128,145"
metadata backgroundColor.section is "Colors"
metadata backgroundColor.label is "Background Color"

private variable mBackFillOpacity as Number
property backgroundOpacity 	   get mBackFillOpacity           set setBackFillOpacity
metadata backgroundOpacity.editor		is "com.livecode.pi.number"
metadata backgroundOpacity.default is "0.5"
metadata backgroundOpacity.min is "0"
metadata backgroundOpacity.max is "1.0"
metadata backgroundOpacity.section is "Colors"
metadata backgroundOpacity.label is "Background Opacity"

handler setBackFillOpacity(in pNum as Number) returns nothing
   put pNum into mBackFillOpacity
   redraw all
end handler

metadata hiliteColor.editor		is "com.livecode.pi.color"
metadata hiliteColor.default is "0,0,0"
metadata hiliteColor.section is "Colors"
metadata hiliteColor.label is "Selected button color"

property boxBorder    get mBorder      set setBorder
metadata boxBorder.editor      is "com.livecode.pi.number"
metadata boxBorder.default     is "10"
private variable mBorder as Number

property boxRaidus    get mRadius      set setRadius
metadata boxRaidus.editor      is "com.livecode.pi.number"
metadata boxRaidus.default     is "15"
private variable mRadius as Number

-- property textFont get mFont set setTextFont
-- metadata textFont.editor is "com.livecode.pi.font"
-- metadata textFont.default     is "Helvetica"
metadata textFont.user_visible is "false"
-- private variable mFont as String
metadata textSize.user_visible is "false"

property labelTextFont get mFont set setTextFont
metadata labelTextFont.editor is "com.livecode.pi.font"
metadata labelTextFont.default     is "Helvetica"
metadata labelTextFont.section is "Text"
metadata labelTextFont.label is "Label Text Font"
private variable mFont as String

property labelTextSize get mFontSize set setTextFontSize
metadata labelTextSize.editor is "com.livecode.pi.number"
metadata labelTextSize.default     is "12"
metadata labelTextSize.section is "Text"
metadata labelTextSize.label is "Label Text Size"
private variable mFontSize as Number

property textAlign get mAlign	 set setAlign
metadata textAlign.editor is "com.livecode.pi.enum"
metadata textAlign.options is "top left,top center,top right,center left,center center,center right,bottom left,bottom center,bottom right,"
metadata textAlign.default is "center center"
metadata textAlign.section is "Text"
private variable mAlign as String

--declare variables:
private variable mPaint as Paint
private variable mTextPaint as Paint

/**
Syntax:
set the opaque of <widget> to {true|false}
get the opaque of <widget>

Summary: `true` if the SVG path is filled; `false` otherwise

Description:
Use the `opaque` property to test or control whether the SVG path is
displayed as filled or not.
*/
private variable mIsOpague as Boolean
property "opaque" get mIsOpague set setIsOpaque
metadata opaque.default is "true"
metadata opaque.label is "opaque"

public handler setIsOpaque(in pBoolean as Boolean)
	put pBoolean into mIsOpague
	redraw all
end handler

----constant:
constant kBuffer is 10

----NEEDED handler, saves the properties of the sidget when stack is saved
public handler OnSave(out rProperties as Array)
	put the empty array into rProperties
	put mText into rProperties["Text"]
	put mBorder into rProperties["boxBorder"]
	put mFontSize into rProperties["textSize"]
	put mAlign into rProperties["textAlign"]
	put mFont into rProperties["textFont"]
end handler

----NEEDED handler, loads the saved properties
public handler OnLoad(in pProperties as Array)
	put pProperties["Text"] into mText
	put pProperties["boxBorder"] into mBorder
	put pProperties["textAlign"] into mAlign
	put pProperties["textSize"] into mFontSize
	put pProperties["textFont"] into mFont
end handler

--HANDLERS to set properties
private handler setText(in pText as String)
	put pText into mText
	redraw all
end handler

private handler setRadius(in pNum as Number)
	put pNum into mRadius
	redraw all
end handler

private handler setAlign(in pText as String)
	put pText into mAlign
	redraw all
end handler

private handler setBorder(in pNum as Number)
	put pNum into mBorder
	redraw all
end handler

private handler setTextFont(in pText as String)
	put pText into mFont
	redraw all
end handler

private handler setTextFontSize(in pNum as Number)
	put pNum into mFontSize
	redraw all
end handler


--CREATE AND DRAW WIDGET:
--OnCreate  This is called when the widget is first created:
public handler OnCreate()
	variable tFont as Font
	variable tFontSize as Number
	variable tFontName as String
	put 0.5 into mBackFillOpacity
	put my font into tFont
   put "A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools.\n\n-Douglas Adams" into mText
	put the size of my font into tFontSize
	put the name of tFont into tFontName
	log [tFontName,tFontSize]
	-- default font size 12
end handler

--OnPaint   This is called on redraw
public handler OnPaint()
	if mIsOpague then
		mpDrawBase(my foreground paint,my background paint,mBorder,mRadius)
	end if
	set the paint of this canvas to my foreground paint
	mpWrapTextinRect(rectangle [mBorder*2,mBorder*2,my width-mBorder*2,my height-mBorder*2],mText,mAlign)

	-- log [my foreground paint,my background paint,mBorder,mRadius]
end handler

private handler mpDrawBase(in pFore as Paint, in pBack as Paint, in pBorder as Number, in pRadius as Number)
	variable tRect as Rectangle
	variable tBackColor as Color

	set the font of this canvas to font mFont at size mFontSize
	put the color of pBack into tBackColor

   set the opacity of this canvas to mBackFillOpacity
	 begin layer on this canvas
	   set the paint of this canvas to solid paint with tBackColor
		put rectangle [0,0,my width,my height] into tRect
		fill rounded rectangle path of tRect with radius pRadius on this canvas
	 end layer on this canvas

		set the paint of this canvas to pFore
		put rectangle [3,3,my width-3,my height-3] into tRect
		fill rounded rectangle path of tRect with radius pRadius on this canvas

		set the paint of this canvas to pBack
		put rectangle [mBorder,mBorder,my width-mBorder,my height-mBorder] into tRect
		fill rounded rectangle path of tRect with radius pRadius on this canvas
end handler

private handler mpWrapTextinRect(in pTextBox as Rectangle,in pText as String,in pAlign as String)
  variable tTextW as Number
  variable tTextH as Number
  variable tMaxRows as Number
  variable tWords as List
  variable tWord as String
  variable tLine as String
  variable tTestLine as String
  variable tRow as Number
  variable tAlign as List
  variable tLinesofText as List

  split pAlign by " " into tAlign
  replace newline with " qzqz " in pText
  split pText by " " into tWords
  set the font of this canvas to font mFont at size mFontSize
  put the height of the layout bounds of text pText on this canvas into tTextH
  put the width of pTextBox into tTextW
  put the floor of ((the height of pTextBox)/tTextH) into tMaxRows
  if tMaxRows = 0 then
	  return
  end if
  put 1 into tRow

  repeat for each element tWord in tWords
	  put tLine & tWord into tTestLine
	  if the width of the layout bounds of text tTestLine on this canvas > tTextW or tWord is "qzqz" then
		  push tLine onto back of tLinesofText
		  put "" into tTestLine
		  if tRow=tMaxRows then
			  put "" into tLine
			  exit repeat
		  end if
		  add 1 to tRow
		  if tWord is "qzqz" then
			  put "" into tLine
		  else
			  put tWord & " " into tLine
		  end if
	  else
		  put tTestLine & " " into tLine
	  end if
   end repeat
	push tLine onto back of tLinesofText

	if element 1 of tAlign is "center" then
		add ((the height of pTextBox)-(tMaxRows*tTextH) + (tMaxRows-tRow)*tTextH)/2 to the top of pTextBox
	else if element 1 of tAlign is "bottom" then
		add ((the height of pTextBox)-(tMaxRows*tTextH) + (tMaxRows-tRow)*tTextH) to the top of pTextBox
	end if

	put 1 into tRow
	repeat for each element tLine in tLinesofText
		set the height of pTextBox to tTextH
  		if element 2 of tAlign is "center" then
	  		fill text tLine at center of pTextBox on this canvas
  		else if element 2 of tAlign is "right" then
	  		fill text tLine at top right of pTextBox on this canvas
  		else
	  		fill text tLine at top left of pTextBox on this canvas
  		end if
		add 1 to tRow
		add tTextH to the top of pTextBox
	end repeat
end handler

public handler OnMouseDown()
   post "mouseDown"
end handler

public handler OnMouseUp()
   post "mouseUp"
end handler

end widget
User avatar
tperry2x
Posts: 3209
Joined: Tue Dec 21, 2021 9:10 pm
Location: Somewhere in deepest darkest Norfolk, England
Contact:

Re: Building NEW 'Classic' Controls

Post by tperry2x »

Could you upload a copy of that stack here Paul, just so I can have a play with it in lite. (With the text widget in). I'd like to see if Lite can handle it or not.
User avatar
OpenXTalkPaul
Posts: 2633
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by OpenXTalkPaul »

tperry2x wrote: Wed Aug 14, 2024 5:59 pm Could you upload a copy of that stack here Paul, just so I can have a play with it in lite. (With the text widget in). I'd like to see if Lite can handle it or not.
Which stack?

I just edited the previous post to include the LabelBox Extension current source code. Save that to a .lcb file and compile with Extension Builder, it will make a stack with widget placed for you when you click 'Test Extension" (in the lower part of that stack)

The other stacks I've posted screens from are all using Widgets you probably don't have installed, they won't work unless they are installed, you'll get light gray fill in a rect where the widget should be instead.
FourthWorld
Posts: 442
Joined: Sat Sep 11, 2021 4:37 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by FourthWorld »

tperry2x wrote: Wed Aug 14, 2024 5:35 pm How about another approach. Yes, machine code or C++ is a lot faster to execute than xTalk Script, but of course it's a behemoth to try and edit this engine - and I'm not sure if anyone has had success in compiling a Windows and MacOS version as of yet based on the last livecode community source code.

However, I wondered about C++ plugins. Whereby the IDE loads the C++ plugin externally and loads it into memory. Yes, there's probably a penalty with startup time in the IDE, but the benefits would be:

1. There's only one C++ file to edit, to make changes, rather than having to recompile the engine completely each time.
2. Updates are easier as you just swap out the C++ plugin
3. You retain the execution speed once the C++ plugin is loaded into memory.

This is just conjecture on my part - I'll defer to someone who's more of a C++ whiz
With HyperCard, SuperCard, OMO, Gain Momentum, Toolbook, Director, Spinnaker Plus, MetaCard, Revolution, and LiveCode, what you describe is the Externals interface.

Indeed nearly all of the key bullet points for the v8 product were externals. They continue to be relied on to this day.
FourthWorld
Posts: 442
Joined: Sat Sep 11, 2021 4:37 pm
Contact:

Re: Building NEW 'Classic' Controls

Post by FourthWorld »

OpenXTalkPaul wrote: Wed Aug 14, 2024 5:51 pm Eh, I'm not sure that's accurate comments in regards to what's actually going on.

LibSkia that draws the widget stuff, it is still C++ compiled code in engine doing the rendering (maybe not the compositing to the card layer), lib LibSkia is exposed to LCB (and can be exposed to script engine too) so it may be called from that intermediate byte code language module that wraps it with binding strings which point to internal engine symbols which then do the work (in the UI thread, not the script execution thread)....
..
That's not to say I haven't noticed some degradation in the Engine's rendering speed over the years...
My assessment of performance is not mine, merely passed on from the company who made Builder.

If you have rendering metrics that favor Builder replacements for machine code, that would be useful for everyone.
User avatar
tperry2x
Posts: 3209
Joined: Tue Dec 21, 2021 9:10 pm
Location: Somewhere in deepest darkest Norfolk, England
Contact:

Re: Building NEW 'Classic' Controls

Post by tperry2x »

OpenXTalkPaul wrote: Wed Aug 14, 2024 6:11 pm
tperry2x wrote: Wed Aug 14, 2024 5:59 pm Could you upload a copy of that stack here Paul, just so I can have a play with it in lite. (With the text widget in). I'd like to see if Lite can handle it or not.
Which stack?
Ah, I thought it would be as simple as attaching the 'LabelBox' stack in your screenshot.
Obviously it's not.

So I had a go.
I copied that code and pasted into a text editor, saving it as labelbox.lcb
I then opened up the IDE and went into Tools > Extensions Builder.
From there, I chose 'Open an existing extension' and selected my labelbox.lcb file I'd made earlier.

I noticed it made all manner of other files:
piles-of-files.png
piles-of-files.png (32.57 KiB) Viewed 5123 times
I then clicked the "Test Extension" in that Extensions Builder window, and indeed I get a new stack called 'LabelBox'. That's the stack I was after, but I'll come back to that.

At first I thought it hadn't worked, but it is there:
fool-1.png
fool-1.png (270.83 KiB) Viewed 5123 times
Note: the label text font was "" and the label text size was 0.
As soon as I set that to a font (Liberation Sans) and 12 under the label text size, it worked and I could change the other properties through the inspector, just as you would a 'classic control'.
fool-2.png
fool-2.png (231.59 KiB) Viewed 5123 times
So, all good.

But, here's where I come back to my question a little further up. When trying to save the stack, I can't. It goes through the motions of saving a stack - but the stack file never appears. I don't get an error or anything either, which means I lose any changes to this new stack, and have to repeat the entire process through 'Extensions Builder' again.

I had hoped it would be a simple oxtstack file that you could copy & paste the 'LabelBox' out of and into a stack of your choice, but it doesn't work like that :?:

Also, I wondered - do these files then need to all live in a subfolder together somewhere? Sorry for all the foolish questions.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest