Oxygen Basic

Programming => Example Code => General => Topic started by: Mike Lobanovsky on November 13, 2014, 05:50:36 PM

Title: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 13, 2014, 05:50:36 PM
Hi,

OxyScheme seems to be starting to show the first signs of life. The code is still dirty and needs much more debugging effort but the core is already there. Don't mind extra debug output while watching OxyScheme as it runs Rob's ASCII Mandelbrot on the left. You can also see the reference nanoscheme script running in FBSL's DynC on the right. :)

P.S. I've got very little spare time for leisure coding these days so I apologize for my sporadic posting. But watch out ye who don't like me: I'm still alive and kicking. ;)

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on November 13, 2014, 06:42:34 PM
Mike,

Will OxyScheme be a custom Lisp version or are you striving for current Scheme compatibility?

You truly have become a Scheme/Lisp expert.

John

Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on November 14, 2014, 03:13:12 AM
Quote
But watch out ye who don't like me

you probably think of me ..and i can say that you are very wrong about that
in fact i really like all your work on fbsl and here on bytecode stuff.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 14, 2014, 03:14:48 AM
Hi John,

OxyScheme/nanoscheme structure follows a standard r4rs Scheme syntax. The later r5rs standard (like in TinyScheme) was introduced mainly to systematize the differences in earlier Scheme implementations and was very close to r4rs in practically everything except a somewhat more laconic notation for the description of new user-defined syntactic forms. Yet everything that's written for TinyScheme can also be described in OxyScheme/nanoscheme's r4rs syntax. And in very many cases, scripts written for TinyScheme are also runnable in OxyScheme/nanoscheme without adaptation.

OxyScheme/nanoscheme has a clear and well-defined modular structure, which makes adding new data types and corresponding functional instrumentarium a relatively straight-forward task. Currently it supports fixnums, flonums and strings only but an eager enthusiast can easily expand it to full numeric tower with exact numbers, chars, and vectors.

I'm planning to support FBSL's nanoscheme script in my spare time in the future and I will naturally be adding the corresponding features to OxyScheme as well. Still I won't mind if someone takes over OxyScheme and then I will be able to augment nanoscheme accordingly.

My only concern at the moment is that judging by the very rough benchmarks that I was able to run to date, OxyScheme appears not so fast as I expected. For example, the doubly recursive fibonacci(35) test yields the following approximate results on my PC:
Currently, OxyScheme's source is a spitting image of its C language original. Hopefully someone will be able to better optimize it for OxygenBasic which was not my own primary goal. I think making such a lengthy and feature rich alien script runnable in OxygenBasic at all is already an achievement in its own right. :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on November 14, 2014, 08:30:30 AM
Quote from: Mike
125 sec for TinyScheme

That's encouraging news. At least I didn't waste my time with the TinyScheme extension module for SB.

 
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on November 15, 2014, 02:16:36 AM
Hi Mike,

I look forward to your final Oxy-Nanoscheme. It will be very useful to discover where further optimisation can be made.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 16, 2014, 06:12:00 AM
Hi Charles,

Do you want me to post the code that hasn't been fully debugged yet? I'm still adding r5rs features to it (mainly numeric stuff) while debugging the rest of it in the process.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on November 16, 2014, 01:50:11 PM
Hi Mike,

Complete your debugging ceremonies first. It will make our interactions much simpler. There is no hurry.

(http://2.bp.blogspot.com/-j6EICwiPWHk/UBmjdmMV3CI/AAAAAAAAAQs/SKDkvL_Ps_Q/s1600/istari_wizards.jpg)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 24, 2014, 02:27:52 PM
OK guys,

So here comes OxyScheme Beta.

1. All procedures and pieces of code that are labeled with '/*...*/ comments belong to the former developers of this code.

2. All procedures and pieces of code that are labeled with C-stylish // comments or not labeled at all have been added by me.

3. The code implements partially (but rather thoroughly) exact and inexact numeric functionality based on integer and double-precision floating-point math. String data type functionality is implemented in full except for its interaction with char data type. Char and complex numeric data types and vectors are not yet implemented.

4. The file nsinit.scm is OxyScheme's initialization file that can be extended to contain a richer library of user-defined procedures and useful macros collected from other sources and adapted to the syntax currently available in OxyScheme. The complete list of internally supported keywords can be found
at the bottom of o2scm.o2bas file (see mk_proc() calls) and additional procedures and macros from nsinit.scm are printed to the console as the file loads at app start.

5. The r5rs manual is included in the zip for you reference as to how an r5rs-compliant Scheme works or should work if bugs are spotted in this Beta version.

6. A few of Rob's .scm samples have also been added for demonstration.

I'm washing my hands of this project for some time (got a little bored with O2's char* pointers ) but your feedback is much welcome nonetheless.


Enjoy! :)

[EDIT] DIS CODE IS IN TEH PUBLIC DOMAIN! ;)

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on November 25, 2014, 04:31:22 PM
Many thanks, Mike.

We must conjure up a few useful applications to put Oxyscheme through its paces. I think the most natural way to interface these Lispish languages is through text i/o, redirected from console to specified APIs: For instance, passing data to SQL, or drawing lists to Opengl via a command interpreter.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on November 25, 2014, 04:39:59 PM
Mike,

When I try to (quit) it goes to the next line (no prompt) and hangs. I have to CTRL-C to exit.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 25, 2014, 09:57:02 PM
Hi John,

I confirm this bug. Please find case OP_QUIT at line 2595 and overwrite this handler with the following code:

Code: OxygenBasic
  1.       case OP_QUIT '/* quit */
  2.        ExitProcess(0)

and also overwrite the main program loop function Eval_Cycle() at line 3271 with the following code:

Code: OxygenBasic
  1.   '/* kernel of this intepreter */
  2.  sub Eval_Cycle(sys op)
  3.     operator = op
  4.     do
  5.       push operator
  6.       call dispatch_table[operator]
  7.     end do
  8.   end sub

This makes things even simpler. :)

Thanks for spotting it!
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 25, 2014, 10:31:22 PM
Many thanks, Mike.

... I think the most natural way to interface these Lispish languages is through text i/o, redirected from console to specified APIs ...

Morning Charles,

My pleasure. :)

I think the most efficient way to interact with 3rd party APIs in DLLs such as OpenGL would be as follows:
:)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 26, 2014, 01:40:10 AM
Oh, and of course this strategy would require that OxyScheme use a non-blocking console implementation in place of its existing ordinary console include file.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on November 26, 2014, 02:32:32 AM
Life is so much more challenging working with an interpreter from a compiler standpoint rather than another interpreter. Is the end goal something like a TinyScheme extension with SB or will it be more tightly coupled?

Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 26, 2014, 03:25:13 AM
At this stage of the project, I'm inclined to regard OxyScheme interop value primarily from its own standpoint rather than that of its vis-a-vises, whatever these may be. In other words, I'm more concerned about its own versatility as a language implementation than about how, say, OxygenBasic could interoperate with such an interpreter. O2 is already a mature language with lots of possibilities to communicate with its environment and siblings. So the immediate task is to grow OxyScheme's own value to such an extent that it can handle its surroundings with competitive ease. Then the two languages will find natural ways and means to benefit from each other's capabilities.

OxyScheme is not a mere extension to OxygenBasic; it is rather a different language implementation in its own right. It's like the relationship between OxygenBasic and FreeBASIC that the former is written in, or thinBasic and PowerBASIC, for that matter. So, the richer OxyScheme becomes as a language, the more points of contact with OxygenBasic will it have to the benefit of the end user.
   
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on November 26, 2014, 03:51:55 AM
I very happy for you and Charles that a comprehensive implementation of the language has been created. DLLC is another such effort in the making. I really thought Eros would have come around by now. He must really love Power BASIC.

@Mike & @Petr - "Romania is just third in the world after the US and UK on the standard of living for IT people."

Is that spilling over into your lives?
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 27, 2014, 05:06:14 AM
@Mike & @Petr - "Romania is just third in the world after the US and UK on the standard of living for IT people."

Is that spilling over into your lives?

Hehe,

Mike lives in Belarus, and Petr lives in the Czech Republic. :)

Well, no John, it isn't. I think Romania's policy is just an indication of how badly is that country in need of qualified IT personnel. But Romania was one of the poorest agrarian regions in the former Eastern Block, and its status is still very close to that in many respects despite its aspiration to join the EU shorty. It is also very close geographically to the self-proclaimed Transnistria region, unrecognized by the European community, that remains yet another hot spot on the map of Europe similar to Eastern Ukraine, due to Russian aggression back in 1990/91.

The Republic of Belarus ranks the 13th (http://belarusfacts.by/en/belarus/economy_business/key_economic/it/) among the world's leading IT countries, and three of our local IT companies are in the list of the top 100 world's largest companies in this industry. Belarusian Wargaming.net is one of the world's leading companies in the modern computer game industry:

(http://www.onrpgblog.com/wp-content/uploads/2012/10/Wargaming-Logo.jpg)

The monthly salary (bonuses excluded) of a post-graduate junior developer here would start at about $1K, which is roughly 4 times the median salary in this country, and a typical project lead's annual income (bonuses excluded) would be on the order of 35 kilobucks and more. A guru senior developer can earn as much as $50K per annum not counting the bonuses. Exactly half of the 15th floor in this building is my elder son's company office:

(http://minsk.rentpost.ru/sites/default/files/imagecache/object_height_400/object/2_289.jpg)


That said, there's absolutely no point for Belarusian programmers and other IT specialists to move to Romania, which would for all intents and purposes be considered as going to exile. However many thousands of them preferred to move directly to Silicon Valley during the past decade escaping the oppressive economic realities of Europe's last dictatorial regime.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on November 27, 2014, 11:13:12 AM
Quote
However many thousands of them preferred to move directly to Silicon Valley during the past decade escaping the oppressive economic realities of Europe's last dictatorial regime.

In the Silicon Valley you can bring your dog to work when times are good and the employee lounges of some of these companies rival Disneyland.

Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on November 27, 2014, 06:13:43 PM
Mike,

I know this may not be of interest now but I thought I would share the find with you anyways. I ran into a nice Commands & Functions list Peter Verhas did and noticed this command I was unaware of.

Quote
POP

Pop off one value from the GOSUB/RETURN stack. After this command a RETURN will return to one level higher and to the place where it was called from. For more information see the documentation of the command GOSUB and RETURN.

I wonder if it would have helped with the SBLisp version of your efforts?

Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on November 27, 2014, 07:18:41 PM
Nice finding John,

It seems it is an equivalent to that QB4.5 functionality that was used to bail out of its error handler. But the bad news is that in order to employ it, we need to keep an exact count and vector of all the levels of app recursion throughout its entire lifetime. (remember the innumerous i_something += 1 statements?)

Such in-/decrementation kills whatever speed SB's interpretative environment has to offer. My last version of the code that I was trying to port to O2 before I switched to nanoscheme eliminated the need to use this pop-and-jump and in-/decrement method completely. I think I'd better stick with my latest version when I'm back to finishing off the SBLisp project code.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 07, 2015, 11:08:57 PM
Hi all,

Coming back to OxyScheme's console interaction with its projected GUI, I'd appreciate your feedback on the following idea of mine.

The Windows console is an odd job that's both crude aesthetically and rather restrictive functionally. Putting it in a non-blocking mode of operation can cure to some extent the latter drawback but it can't alter the former one in any way. So what if we design an altogether custom GUI-based "console" rather than beating about the bush with the system "command prompt" window?

The "console" will be just an ordinary GUI window within the same message pipe as (an)other output window(s) in OxyScheme's common GUI environment, thus making the entire setup much more flexible and less susceptible to possible bottlenecks of true console-to-GUI interface. Moreover, OxyScheme's graphical output can even be redirected to this very "console" persistently (i.e. made not susceptible to erasure by overlapping windows), if needed, which is impossible with MS Windows' true command prompt whose message pipe is programmatically absolutely inaccessible for the user.

To cut the story short, here's a very rough mockup of what such a "console" might look like. It currently supports:
The mockup is even functional, more or less, under OSX and Linux Wine except for its blur feature, apparently due to some deficiencies in GDI+/layered window re-implementation in Wine's GUI.

With a little more effort the "console" may be extended to support:

What would you say to that, guys?

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 08, 2015, 12:02:15 AM
That is very fine and nice Mike..far far better than ordinary console app...
semi transparency with shadow effect is excellent  ;)
I like it.
Only thing is that i cannot grab capture of window with my fastStone viewer..
all in all very well  ;)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on January 08, 2015, 01:13:49 AM
Hi Mike,

The concept of a graphical console has great potential - can you make translucent console windows with OpenGl?

Most of my recent graphical work, including Chain-Shot, has used this kind of GUI. Editable line inputs can be a little complicated, but well worth the effort to be able to blend interactive text and graphics, and to display data outputs in graphical form:

projectsA/OpenglCns/

In the example below, the title and the graph can be moved, rotated or stretched for optimal viewing and snapshots.

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 08, 2015, 09:14:38 AM
Evening Charles,


Not only can I make a translucent standalone window in OpenGL but I can also create a translucent OpenGL overlay within an OpenGL-compatible variable-translucency GDI+ window similar to the one implemented in the mockup!

A beautiful piece of such interactive GDI+/OpenGL compatibility originally implemented in PowerBASIC is attached below. It is just one sample among a ton of amazing submissions written by Patrice Terrier and available at José Roca's site on its GDImage and other relevant subforums.

Patrice's graphical engine however has some serious license restrictions IIRC. On the other hand, OxyScheme is a Public Domain project and I would like it to remain as such. My mockup doesn't use nor mimic a single code line in Patrice's works though of course the basic principles utilized in both approaches are similar and are built around MS Windows' inner workings.

Using OpenGL to implement relatively slow (CPU-wise) textual input-output would IMHO be like using a sledgehammer to crack a nut. The same can effectively be done using GDI+ alone. GDI+ is a system library on every MS platform starting with XP Sp3. The mockup's rendering part is written entirely in FBSL's unoptimized interpretative BASIC except for its highly efficient stack blur procedure that must be as fast as possible at all times and therefore was written in JIT DynC in this implementation.

(Stack blur is a Public Domain adjustable high-performance image blurring algo that of course isn't as good as genuine Gaussian blur but is much better visually and also much, much faster than its direct competitor, the box blur algo. It is in fact so fast that it can even be used for harware unassisted quality blurring of relatively small areas in real time as shown in this mockup.)

Further, GDI+ allows any number of screen windows to be rendered simultaneously in a single process. OTOH OpenGL allows only one physical window to be rendered per process. This effectively means that if we want to use a separate window for OxyScheme's graphical output, we won't be able to do that because OpenGL would already be busy rendering our "console".

But again, if we would prefer to render (some) OpenGL into the "console" window proper, there would be nothing to prevent us from creating an (optionally translucent) OpenGL overlay for the "console" window region where we would like to render to. Then again, the number of yet other possible concurrent GDI+ windows in the process would remain unlimited.

And finally, using a common set of background bitmaps and common skinning/rendering engine for all the windows in the process regardles of their number would create a visually uniform yet adjustable GUI system pleasant to the eye.


Your move, sir. :)

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on January 08, 2015, 10:32:48 AM
Quote from: Mike
It is just one sample among a ton of amazing submissions written by Patrice Terrier ...

Patrice in his spare time created the Script BASIC logo years ago. I have used Patrice for other projects on a fee basis.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 08, 2015, 11:15:28 AM
Yes John, the SB logo is an absolutely professional piece of art. In fact, I've never had any doubt you had to pay cash to have it designed for you. :)

Yes, I know Patrice has a sorta IT atelier and is likely to make a good deal of his living off of it. I admire almost all of his works very much. He's an artist in the first place and a solid and creative developer too.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on January 08, 2015, 11:57:39 AM
Quote from: Mike
I've never had any doubt you had to pay cash to have it designed for you.

The SB logo Patrice did was his contribution to the open source project. I hired him for artwork for client projects in the past.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 08, 2015, 12:23:23 PM
Does that change in any way the subject of his being an artist or his z-whatever rendering engine being under a restrictive license? I'm glad though that you managed to save a coupla bucks for better uses. :)

P.S. And by the way, can you provide any feedback on the subject matter of my graphical "console" proposition? Even if MS Windows is not your preferred environment.



@Robbek:

I would like to hear your opinion on OxyScheme and its graphical "console" too, if possible. I haven't seen a single message of yours in this thread so far. Or are you not interested in the subject? :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 08, 2015, 12:44:39 PM
Quote from: Charles
... can you make translucent console windows with OpenGl?

Oh Charles,

I just thought that perhaps I misunderstood your question. If you mean whether we can apply OpenGL to Windows genuine console window, either in its non-client or client parts, then I'd say no, we can't. The genuine console's main callback is inaccesseble in the user space nor can it be subclassed. The only two things one can do is get the console hWnd and its graphics hDC for occasional non-persistent GDI drawing. Every other activity on the user side is totally blocked by the system except for ordinary access to its input/output and screen buffers.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on January 08, 2015, 12:57:32 PM
Quote from: Mike
P.S. And by the way, can you provide any feedback on the subject matter of my graphical "console" proposition? Even if MS Windows is not your preferred environment.

I would love to but ...

Other than the above, I do try to visit the O2 forum and maybe post something if I have time.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on January 08, 2015, 01:17:50 PM
Thanks Mike,

Your previous interpretation is what I had in mind.

I have found that it is possible to run Opengl in at least 2 child windows. The trick is to use a single rendering context (hRC) and then for each child window, select the device context  (wglMakeCurrent hDC, hRC ), render it, and SwapBuffers. This may not work for all video cards, but certainly for NVidia.

There are 2 rather old examples in examples/OpenGl/other/
OpenGlChildWins1.o2bas
OpenGlChildWins2.o2bas

Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 08, 2015, 01:25:34 PM
I'm really sorry to hear all that, John, and especially about that misfortunate incident with your daughter. Let me still wish you luck and prosperity in your business matters, and all the best to your small family in the New Year 2015. We must always hope for the better and never lose heart before the obstacles. I can hardly be of any more help to both of you than just some verbal support like that but I promise to keep my fingers crossed for my wishes to come true.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 08, 2015, 01:46:44 PM
I have found that it is possible to run Opengl in at least 2 child windows. The trick is to use a single rendering context (hRC) and then for each child window, select the device context  (wglMakeCurrent hDC, hRC ), render it, and SwapBuffers. This may not work for all video cards, but certainly for NVidia.

Yes Charles,

I'm aware of this technique but thanks anyway for pointing it out once again. Splitting the render frame period between two contexts and especially allowing two or more SwapBuffer() calls can be unbearable for OpenGL if at least one render is heavily populated with objects. In any case, relying on this technique as the basis for one's project means going far beyond the borderline set forth in the OpenGL Specs. It may set up a physical limit to how complex an OpenGL task may be for an off-"console" render target and of course there will always be a slim chance that some proprietary video driver other than nVidia will not support that just because that's not required in, or is directly discouraged by, the Specs.

Talking about general feasibility of a graphics console emulation, I'm still in favor of GDI/GDI+ solutions to have my hands absolutely free and allow OpenGL tasks of any complexity on the user side of OxyScheme's programming environment.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on January 09, 2015, 12:36:04 PM
Hi Mike,

I have not yet found a need to use multiple Opengl windows, but the potential restriction seems a little strange when multiple processes, using Opengl, operate without mutual hindrance.

Anyway, I look forward to seeing your crystal console :)

Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 11, 2015, 01:53:14 PM
Thanks for encouragement, Charles! :)

Scared as I am to proceed with the printing engine proper (reimplementing the genuine console's screen buffer is supposed to be one hell of a job), here are a few more bells and whistles for the window.

Just found a cheap down-/upsampling trick that yields some nice visual effects without the elaborate per-pixel stack blur algo. Also button and menu controls implemented (ugly coompared to Patrice's art but will do for the moment).

The tiles are actually down-/upsampled images of the icons beneath the window on my right-side monitor. Reflection works only on the main (central) monitor that's why it isn't seen even though enabled.

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 13, 2015, 11:10:36 AM
Hi all,

I'm done with bells and whistles. Now I would like to know very much if restored and maximized windows can be dragged smoothly enough on your screens. On my PC, unblurred maximized windows and blurred restored windows slide absolutely smoothly without any visible lag of image within the window. Blurred maximized windows do lag a little bit but no more than a large MDI window would, such as e.g. a Code::Blocks or MS Studio IDE. So I think that's about it as far as prettifying the "console" goes.

Note that blur is still disabled automatically in genuine Aero modes but I think I've found a way to make it compatible. However a little more experimentation will be needed to (dis)prove it.

Please let me know what you see on your screens.

Thanks!

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 13, 2015, 02:32:32 PM
Hi Mike
it work fine on my old comp but little bit slow, i mean there is a delay in moving window
and again i cannot get screen capture with my image viewer...
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 13, 2015, 09:41:15 PM
Hi Aurel,

Thanks for your feedback. When focus is on this window, use Alt + PrtScr to capture its image into the clipboard, and then Ctrl + V or Shift + Ins to insert it into MS Paint or any other image viewer or editor. It is a layered window and perhaps your viewer just isn't designed to capture them.

Do you mean there is a delay in moving the window even when it's small? Is it still slow even when blur amount is zero (when the blur button is in its leftmost position)?
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on January 14, 2015, 04:08:49 AM
Hi Mike,

The expanded window, with its default settings, can be moved around the screen with about 5 -7 refreshes per second, which seems perfectly acceptable to me.

(system : 2 gig quad-core  Vista 64, XP mode)

Charles
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 14, 2015, 05:33:03 AM
Hi Charles,

Thanks, that's good news. I've checked it on a 2.2GHz Core2 Duo and found out that unblurred windows, both expanded and smaller ones, move smoothly like ordinary layered windows should. Same for smaller blurred windows where there's practically no tear. Expanded blurred ones do show some bearable tear. I'll add an option to pin the expanded windows to the screen top left/right corners to discourage dragging them around on slower computers.

I could've also made the window resizable by its borders/corners but the visual effect isn't very nice, so I subsided to just two fixed sizes for the moment. In future, I can also add per-line resizing by the lower border like in the original console. But that will be done later when the time to design text scrolling comes and the client area metric parameters are worked out.

Tomorrow I'm starting to move to a new residence, which is going to take some time. I'll be keeping an eye on the forum but I won't be fully functional until after this weekend.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on January 14, 2015, 09:29:25 AM
Good luck with your move!

(http://cache.graphicslib.viator.com/graphicslib/thumbs674x446/3595/SITours/christmas-horse-drawn-sleigh-ride-from-salzburg-in-salzburg-145684.jpg)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 14, 2015, 11:07:17 AM
Yes Mike when is blur on minimum then there is no delay ..interesting..
oh man i never liked this openGL stuff ::)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 14, 2015, 12:08:01 PM
Aurel, this is not OpenGL, this is entirely GDI+ stuff. Good quality blur is a very computationally intensive task even for modern fast CPUs. It would probably be more reasonable to have it disabled (set to 0) on slower PCs. A crystal-clear/colored layered window also seems to be looking quite nice without blur.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 14, 2015, 12:26:19 PM
Thanks, Charles!

There are no mountains, nor horses, nor sledges, nor even snow here at the moment. :)

After living for over 6 years in the city of Brest that's situated on the Belarusian-Polish border, I'm finally moving back to Minsk, the country's capital 300 miles farther into the continent, where I'd used to reside for over 35 years before I came to Brest.

The red arrow in the picture below shows the apartment house I'm going to live in, and this link (https://www.youtube.com/watch?v=2aq1-fNxWN0) will show you how beautiful my home town really is. :)

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 14, 2015, 02:26:01 PM
Quote
this is entirely GDI+ stuff
then ok !
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 01:42:24 AM
Guys,

I know how to make full-window dragging around the screen more pleasant to the eyes and avoid this annoying tear altogether on slower computers. The visual trick is similar to dragging-and-dropping files from window to window under MS Windows and Linux, and it also had its direct analog using the PowerWindows extension under MacOS 9 not so long ago. The ghost window will replicate its parent in everything except blur, and it will also be made much more translucent to stress its temporality while dragging. (please see the attached .AVI)

Yet another option can be to avoid this ghost window altogether and switch off the blur and make the window itself semi-translucent while it is being dragged around, and then to restore its blur, alpha, and color parameters once it is dropped at its target location. Aurel has confirmed that a non-blurred translucent window can be dragged smoothly enough even on a slow PC.

What would you say to that, please?

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 15, 2015, 01:59:24 AM
Mike
You know that i don't have interest for this OxyScheme BUT
i would like to try this interpreter.
Is there any compiled version with few examples that anyone who is interested can try?
thanks!
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 02:07:48 AM
Aurel,

It was posted in this very topic earlier in November last year. (http://www.oxygenbasic.org/forum/index.php?topic=1251.msg12337#msg12337) :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 15, 2015, 02:16:12 AM
Mike
Ok when i compile this source i get this error.
Do you can add your compiled version (exe)?

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 02:53:46 AM
Here it goes precompiled with the latest version of OxygenBasic.

nsinit.scm is the interpreter initialization file that's loaded automatically at app start. The other three .scm files are Rob's examples.

The .scm file can be loaded and executed through typing e.g. (load "asciim.scm") and hitting Enter. You can quit the interpreter by typing (quit) + Enter. Many much simpler examples can be found in the r5rs reference manual that's included in the zip that I posted in November. Just type a test command (or sequence of commands) exactly as it is (they are) written in the manual making sure to match the number of opening/closing parentheses in proper places.

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 15, 2015, 03:00:25 AM
sorry Mike
i do exectly what you say and ..nothing ::)


.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 15, 2015, 03:02:50 AM
..and also by d&d into oxyscheme exe ...i get this:


.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 03:09:19 AM
1. No, you are not. I told you to type (load "asciim.scm"). Now, where are your parentheses in your snapshot?

2. You shouldn't use OxyScheme without its nsinit.scm file because the interpreter will work but will lose much of its extended functionality. Make sure nsinit.scm is put alongside (i.e. in the same folder with) OxyScheme.exe. Also, it wouldn't work with d&d because it needs to load its initialization file first but d&d overrides this behavior.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 15, 2015, 06:06:10 AM
The ultimate solution is to work in full composited mode, and render everything onto the DWM DirectDraw surface.

...
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 09:25:26 AM
Hi Patrice,

Pleased to meet you! :)

Thanks for the hint. I got its secret meaning and my first hit when googling for the subject matter was your remarkable article on CodeProject dot com (http://www.codeproject.com/Articles/705243/HUD-window-bit-DWM-composition) dated January 2, 2014. I also read its accompanying license (http://www.codeproject.com/info/cpol10.aspx) carefully and I found out that its terms were OK by me in all respects.

I'm going to study your material at length and see what parts of it are applicable to my humble project.

At any rate, thanks again for sharing your knowledge and your code that I've always found to be of great educational and practical value.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on January 15, 2015, 09:48:45 AM
Welcome Patrice!

Glad you decided to join us and looking forward to seeing some of your magic working in OxygenBasic.



Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 15, 2015, 10:28:47 AM
Quote
for the subject matter was your remarkable article on CodeProject dot com dated January 2, 2014
The article was bookmarked only 19 times...
Meaning that very few undesrtood it, probably because its purpose is too different of what they are accustomed to.

I like those Avatar/Oblivion transparent display, prefiguring the next TV generation.

 :)

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Charles Pegge on January 15, 2015, 10:41:09 AM
Mike,

Your ghost-dragging  solution is ingenious. Your work on this problem is intensive! :)

I'm toying with very simple whole-window transparency. The sweet spot seems to be an alpha value of around 240 (/255), so the background is slightly visible, but not intrusive.

Proposed switch for Oxygen OpenGL apps etc: % WindowOpacity 240

This code is deployed in inc/WinUtil.inc WinMain, above ShowWindow

Code: OxygenBasic
  1.   #ifdef WindowOpacity
  2.     'Set WS_EX_LAYERED on this window
  3.    SetWindowLong(hwnd, GWL_EXSTYLE,
  4.     GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED)
  5.     SetLayeredWindowAttributes(hwnd, 0, WindowOpacity, LWA_ALPHA);
  6.   #endif
  7.  

But Snapshot (Ctrl P) captures the client area before composite transparency is applied. ie: from the frame buffer with glReadPixels.


.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 11:56:20 AM
The article was bookmarked only 19 times...
Meaning that very few undesrtood it

In fact, you've never had a more dedicated reader, student and admirer on your board at José Roca's forum in years than me. :)

I don't own a copy of PB/Win to try your solutions myself in their raw form but it isn't too difficult for an experienced Basic-er to judge their beauty and also the tremendous amount of implicit effort put into concomitant investigation, trial and error behind the code that you made available to public at large so generously and abundantly. Thanks for your creative work on behalf of those in the know. :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Aurel on January 15, 2015, 12:41:01 PM
Mike
you have a right i forget to add brackets  ::)
now work  ;)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 02:20:23 PM
Great!

( [] --> brackets, {} --> braces, () --> parentheses )
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 15, 2015, 02:20:41 PM
Using a layered window would be the easiest solution.

Something like this (the code is the same in Basic)
Code: [Select]
void RenderWindow(IN HWND hWnd, IN LONG_PTR hImg) {
    if (hImg) {
        BLENDFUNCTION bf = {0};
        RECT rw; GetWindowRect(hWnd, &rw);
        SIZEL lpSize; lpSize.cx = rw.right - rw.left; lpSize.cy = rw.bottom - rw.top;
        POINT lp; lp.x = rw.left; lp.y = rw.top;
        POINT ptSrc = {0};
        HDC hParentDC = GetDC(GetParent(hWnd));
        HDC hMemDC = CreateCompatibleDC(hParentDC);
        HBITMAP hBmp = CreateCompatibleBitmap(hParentDC, lpSize.cx, lpSize.cy);
        if (hMemDC) {
            SelectObject(hMemDC, hBmp);
            LONG_PTR graphics = 0;
            if (GdipCreateFromHDC(hMemDC, graphics) == 0) {
                GdipDrawImageRectRectI(graphics, hImg, 0, 0, lpSize.cx, lpSize.cy, 0, 0, lpSize.cx, lpSize.cy, 2, 0, NULL, NULL);
                GdipDeleteGraphics(graphics);
            }
            bf.BlendOp             = AC_SRC_OVER;
            bf.BlendFlags          = 0;
            bf.AlphaFormat         = AC_SRC_ALPHA; // Use source alpha
            bf.SourceConstantAlpha = 255;          //alpha
            UpdateLayeredWindow (hWnd, hParentDC, &lp, &lpSize, hMemDC, &ptSrc, 0, &bf, ULW_ALPHA);
            DeleteObject(hBmp);
            DeleteDC(hMemDC);
        }
        ReleaseDC(GetParent(hWnd), hParentDC);
    }
}


Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 02:34:57 PM
Yes Patrice,

Thanks for the tip. In fact, my proto already uses a layered window and a similar, albeit a little more elaborate, render proc with a few more render stages from various in-memory resources including Gdip images and pixel buffers where blur takes place selectively. Text lines are rendered the last.

My "mother tongue" is FBSL whose JIT compiler accepts classic ANSI C. That's why I don't publish the quick prototype's alien code here, but rather a precompiled executable only, until it's well polished and is ready to be ported to native OxygenBasic.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 15, 2015, 03:08:25 PM
Charles,

Your ghost-dragging  solution is ingenious. Your work on this problem is intensive! :)
Thanks go to the late Steve Jobbs. :)

Quote
I'm toying with very simple whole-window transparency. The sweet spot seems to be an alpha value of around 240 (/255), so the background is slightly visible, but not intrusive.
My proto uses an alpha value of 250. Then the general outline of another layered window underlying the blurred "console" can yet be recognized while setting full opacity would still make the "console" pass for a completely non-transparent window, especially if it is heavily colored. BTW, Patrice's original SkinBox sources didn't know this alpha tweak and, when blurred, made the underlying layered window completely invisible. Probably this was the very reason why only one SkinBox process could be launched at any one time by Patrice's design. :D

Quote
    SetLayeredWindowAttributes(hwnd, 0, WindowOpacity, LWA_ALPHA)
If you aren't planning to change the attributes often, then perhaps Patrice's
UpdateLayeredWindow (hWnd, hParentDC, &lp, &lpSize, hMemDC, &ptSrc, 0, &bf, ULW_ALPHA);
with the associated BLENDFUNCTION bf structure would be sufficient to produce the desired effect. According to MS specs, SetLayeredWindowAttributes() can be cumbersome. Luckily it may (and should) be omitted unless absolutely necessary. My proto doesn't use such a call at all, only UpdateLayeredWindow ().

By the way, there's a later version of my proto with yet some more bells and whistles on the FBSL forum (http://www.fbsl.net/phpbb2/viewtopic.php?f=4&t=3060#p10677). It is now pinnable to the screen's upper corners and visually responsive to app activate events and double clicks to maximize and restore the window.

Quote
But Snapshot (Ctrl P) captures the client area before composite transparency is applied. ie: from the frame buffer with glReadPixels.
I can't comment on this in any way because I don't know the inner workings of Oxygen's Snapshot feature yet. :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: JRS on January 15, 2015, 03:09:47 PM
Quote
My "mother tongue" is FBSL whose JIT compiler accepts classic ANSI C. That's why I don't publish the quick prototype's alien code here, but rather a precompiled executable only, until it's well polished and is ready to be ported to native OxygenBasic.

Using a good interpreter to prototype projects is a great way to see progress and define direction before starting on a compiled (production) version of it.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 16, 2015, 12:22:48 AM
UpdateLayeredWindow, is very fast, making it suitable for animation, it needs to be used {only} when the content of the window has changed, it writes directly onto the DirectDraw surface, meaning all the hard work of composition with the background or the other overlayed popup window is done by DWM.

And since Windows 8, the WS_EX_LAYERED style can also be used with child windows.

Blur effect has been removed from Windows 8, to reduce drastically the extra work for the graphic card.

I would never try to force transparency directly onto an OpenGL render context, but delegate this task to DWM because everything including OpenGL is ultimatly drawn on the DirectDraw surface with a fixed refresch rate of 60Hz.

The main advantage of a {true} layered window is that it could have empty region and variable opacity, while a {standard} layered window apply the same transparent level to all the child controls belonging to a specific popup window, that is very restrictive.

...




Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 16, 2015, 12:37:16 AM
Hi Patrice,

everything including OpenGL is ultimatly drawn on the DirectDraw surface with a fixed refresch rate of 60Hz.

Are you talking about VSync here? If yes then what about wglSwapIntervalEXT(0) to disable altogether whatever VSync'ing mode the OpenGL driver is currently in (30FPS/60FPS/adaptive)?
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 16, 2015, 02:10:53 AM
You should never use the OpenGL VSync with DWM (when AERO mode is enabled).
And starting with Windows 8+ the AERO mode is now always on.

The ultimate OpenGL setting is to apply the correct wglChoosePixelFormatARB and use the good PIXELFORMATDESCRIPTOR to build the best RC with wglCreateContext.
This is what the GDImage WGL_CreateWindow API does to create state of the art graphic scene (see the SkinnedChart project).

By the way, i didn't know what FBSL was, before you name it in one of your previous post :)

I use only the core Windows procedural flat API, because it is the only way i found to switch {easily} between all the different programming environment i am using.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 16, 2015, 05:29:37 AM
Luckily, I'm not using OpenGL for this project but rather GDI+ only while Charles seems quite content with being restricted to 60FPS only in his OpenGL solutions. We used to discuss it in the past. :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 16, 2015, 06:53:20 AM
Quote
Luckily, I'm not using OpenGL for this project but rather GDI+

GDIPLUS works like a charm with DWM, especially in the AERO "crystal" mode.
The problem arise when using GDI32 and standard Windows controls, that are repainting themselves in 24-bit rather than 32-bit (aka RGB color, rather than ARGB/BGRA).
In this case the solution is to subclass the controls and perform a WM_PRINT with a 32-bit DIB DC, inside of the WM_PAINT message, and use GDI+ to draw the WM_PRINT image with the correct alpha channel.

...
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 17, 2015, 04:42:45 PM
Thanks again Patrice,

That hint of yours has just helped me to imprint the console's vertical scrollbar into its "client" area. :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 18, 2015, 12:41:35 AM
Mike--

Cut and past of the code i am using inside of WinLIFT to skin ListBox and the Combo ListBox part,
the principle is the same with all the GDI32 child controls.

Code: [Select]
         switch (nCtrlType) {
         case CTRL_LISTBOX:
         case CTRL_COMBOLISTBOX:
              if (ListCount(hWnd) > 0) { // To deal with the DWM_AERO mode
                  if ((nCtrlType = CTRL_LISTBOX) && (skGetSystemMetrics(SK_DWM_AERO))) {
                      skChildOffset(hWnd, ofX, ofY);
                      if (wParam == 0) {
                          BeginPaint(hWnd, &ps); hDC = ps.hdc;
                      } else {
                          hDC = (HDC) wParam;
                      }
                      hDCmem = skOFFscreen(hDC, Xin, Yin, 1);
                      CallWindowProc(ChildMessage, WM_PRINTCLIENT, (WPARAM) hDCmem, lParam);
                      if (GdipCreateFromHDC(hDCmem, graphics) == 0) {
                          GdipCreateBitmapFromHBITMAP((HBITMAP) GetCurrentObject(hDCmem, OBJ_BITMAP), NULL, img);
                          GdipDrawImageRectI(graphics, img, 0, 0, Xin, Yin);
                          if (img) { GdipDisposeImage(img); }
                          GdipDeleteGraphics(graphics);
                      }
                      skOFFscreen(0, 0, 0, 0);
                      if (wParam == 0) { EndPaint(hWnd, &ps); }
                      return 0;
                  } else {
                      nRet = CallWindowProc(ChildMessage, uMsg, wParam, lParam);
                  }
              } else { // in case of empty ListBox
                  skChildOffset(hWnd, ofX, ofY);
                  if (wParam == 0) {
                      BeginPaint(hWnd, &ps); hDC = ps.hdc; }
                  else {
                      hDC = (HDC) wParam;
                  }
                  hDCmem = skOFFscreen(hDC, Xin, Yin, 1);
                  if (nCtrlType == CTRL_LISTBOX) {
                      skAlphaBlend(hDCmem, 0, 0, Xin, Yin, skGetHdcMemBmp(skPopupOwner(hWnd)), ofX, ofY, Xin, Yin);
                      skShadowBlt(hDCmem, 0, 0, Xin, Yin, skGetSysColor(SKCOLOR_SHADOW), skGetSystemMetrics(SK_TRANSLUCENCY));
                  } else { // 4.61 CTRL_COMBOLISTBOX
                      skFillRect(hDCmem, 0, 0, Xin, Yin, skGetSysColor(SKCOLOR_EDITCOLORBACK));
                  }
                  skOFFscreen(0, 0, 0, 0);

                  if (wParam == 0) { EndPaint(hWnd, &ps); }
                  return 0;
              }
              break;
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 18, 2015, 10:31:27 PM
Yes Patrice,

That piece with WM_PRINTCLIENT is basically what I'm doing in my render proc too except that my only control I'm currently working with is a vertical scrollbar.

It seems to draw statically OK and it is responsive to mouse hover events (i.e. it redraws as expected when skinned). I'm drawing it on an alpha=250 GDI+ canvas so it looks almost opaque but not quite, which is sufficient for me to know it draws exactly as I expect it to.

However I'm not seeing it behave as a default control should if both the dialog and control were non-layered. It's thumb should be draggable with the left button down, and the left button down on its bottom arrow icon shouldn't redraw the icon.

Contrary to that, I can't drag the thumb down and I also get the bottom arrow icon unpainted when I press the mouse's left button on it. At the same time, the messages in both the control window and main dialog seem to be flowing as usual. I'm curious what the cause of such misbehavior might be.

.
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 19, 2015, 12:53:09 AM
This is because the horizontal and vertical window's scrollbar are not real controls.
Indeed thay are drawn directly by the OS itself when it paints (WM_NCPAINT) the frame of a window popup or child window.

Tooks me years to figure how to handle them correctly into WinLIFT...
http://forum.pcsoft.fr/es-ES/pcsoft.fr.horssujet/2500-skins-gabarits/read.awp

And my solution was to draw everything myself using a region, to defeat Windows redrawing hover my nice skin and using a specific control of my own as the container.

Nothing easy as you would see below:
Code: [Select]
LRESULT CALLBACK ScrollBarProc(IN HWND hWnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) {
    LRESULT nRet = 0;
    RECT rc = {0}, rw = {0};
    PAINTSTRUCT ps = {0}; POINT p = {0}; SCROLLBARINFO sbi = {0}; SCROLLINFO si = {0};

    HDC hDC = 0, hDCpaint = 0; HRGN hRgn = 0, hRgnClip = 0;
    HWND hMain = 0, hParent = 0;
    long x = 0, y = 0, w = 0, h = 0, xX = 0, yY = 0, UseSB = 0, nState = 0, ofX = 0, ofY = 0, hH = 0;
    long UseState = 0, dxy = 0, dxy1 = 0, dxy2 = 0, nDelta = 0, K = 0, nCtrlType = 0;

    static long TimerDelay, ThumbMoving, ThumbX, ThumbY;

    long nItem = GetScrollParent(hWnd, hParent);

    if (nItem > -1) {
        switch (uMsg) {
        case WM_TIMER:
             if (IsLButtonDown()) {
                GetWindowRect(hWnd, &rw);
                GetCursorPos(&p);
                x = p.x - rw.left; y = p.y - rw.top;
                if (SBmouseCheck(hWnd, hParent, UseSB, x, y, nItem, ThumbMoving)) { return nRet; }
                }
             else {
                if (TimerDelay) { KillTimer(hWnd, 1); TimerDelay = 0; }
                ReleaseCapture();
             }
             break;

        case WM_MOUSEMOVE:
             if (ThumbMoving) {
                 nCtrlType = g_Child[skChild(hParent)].CtrlType;
                 GetCursorPos(&p);
                 sbi.cbSize = sizeof(sbi);
                 if (ThumbMoving == THUMB_HORZ) {
                     if (nCtrlType == CTRL_ZIMAGECTRL) {
                         si.cbSize =  sizeof(si);
                         si.fMask  = SIF_ALL;
                         GetScrollInfo(hParent, SB_HORZ, &si);
                         GetScrollBarInfo(hParent, OBJID_HSCROLL, &sbi);
                         dxy1 = sbi.rcScrollBar.left + sbi.dxyLineButton;
                         dxy2 = sbi.rcScrollBar.right - sbi.dxyLineButton;
                         p.x -= (sbi.xyThumbBottom - sbi.xyThumbTop) / 2;
                         nDelta = dxy2 - dxy1; if (nDelta == 0) { nDelta = 1; } // 10-31-2013 Avoid divide by zero
                         //dxy = (min(max(p.x, dxy1), dxy2) - dxy1);
                         //dxy = (long) (dxy * ((si.nMax - si.nMin) / (float) nDelta));
                         dxy = (long) ((min(max(p.x, dxy1), dxy2) - dxy1) * ((si.nMax - si.nMin) / (float) nDelta));

                         if (dxy != si.nPos) {
                            if (TimerDelay) { KillTimer(hWnd, 1); TimerDelay = 0; }
                            si.nPos = dxy;
                            SetScrollInfo(hParent, SB_HORZ, &si, TRUE);
                            skRedrawWindow(hParent);
                         } }
                     else {
                         nDelta = (p.x - ThumbX); ThumbX = p.x;
                         if (nDelta > 0) {    // To the right
                             UseSB = SB_LINERIGHT; }
                         else {               // To the left
                             UseSB = SB_LINELEFT;
                         }
                         for (K = 0; K < abs(nDelta); ++K) {
                             if (IsLButtonDown() == 0) {
                                ThumbMoving = 0;
                                if (TimerDelay) { KillTimer(hWnd, 1); TimerDelay = 0; }
                                ReleaseCapture();
                                break;
                             }
                             SendMessage(hParent, WM_HSCROLL, MAKLNG(UseSB, 0), 0);
                         }
                     } }
                 else {
                     si.cbSize =  sizeof(si);
                     si.fMask  = SIF_ALL;
                     GetScrollInfo(hParent, SB_VERT, &si);
                     GetScrollBarInfo(hParent, OBJID_VSCROLL, &sbi);
                     dxy1 = sbi.rcScrollBar.top + sbi.dxyLineButton;
                     dxy2 = sbi.rcScrollBar.bottom - sbi.dxyLineButton;
                     
                     if (nCtrlType == CTRL_ZIMAGECTRL) {
                        p.y -= (sbi.xyThumbBottom - sbi.xyThumbTop) / 2;
                     }
                   
                     nDelta = dxy2 - dxy1; if (nDelta == 0) { nDelta = 1; } // 10-31-2013 Avoid divide by zero
                   
                     //dxy = (min(max(p.y, dxy1), dxy2) - dxy1);
                     //dxy = (long) (dxy * ((si.nMax - si.nMin) / (float) nDelta));
                     dxy = (long) ((min(max(p.y, dxy1), dxy2) - dxy1) * ((si.nMax - si.nMin) / (float) nDelta));

                     if (dxy != si.nPos) {
                         InvalidateRect(hParent, NULL, 0);
                         switch (nCtrlType) {
                         case CTRL_LISTVIEW:
                              SendMessage(hParent, LVM_ENSUREVISIBLE, dxy, 0);
                              break;
                         case CTRL_LISTBOX:
                              SendMessage(hParent, LB_SETTOPINDEX, dxy, 0);
                              break;
                         case CTRL_SYSTREEVIEW:
                              SendMessage(hParent, WM_VSCROLL, MAKLNG(SB_THUMBTRACK, dxy), 0);
                              break;
                         case CTRL_EDIT:
                              SendMessage(hParent, WM_VSCROLL, MAKLNG(SB_THUMBTRACK, dxy), 0);
                              break;
                         case CTRL_ZIMAGECTRL:
                              if (TimerDelay) { KillTimer(hWnd, 1); TimerDelay = 0; }
                              si.nPos = dxy;
                              SetScrollInfo(hParent, SB_VERT, &si, TRUE);
                              skRedrawWindow(hParent);
                              break;
                         }
                     }
                 }
             }
             break;

        case WM_LBUTTONDOWN:
             x = LOINT(lParam); y = HIINT(lParam);
             if (SBmouseCheck(hWnd, hParent, UseSB, x, y, nItem, ThumbMoving)) { return nRet; }
             ReleaseCapture();
             SetCapture(hWnd);
             if (GetFocus() != hParent) { SetFocus(hParent); }
             if (TimerDelay) { KillTimer(hWnd, 1); TimerDelay = 0; }
             if (ThumbMoving == 0) {
                TimerDelay = 50; SetTimer(hWnd, 1, TimerDelay, NULL); }
             else {
                GetCursorPos(&p);
                ThumbX = p.x; ThumbY = p.y;
             }
             return nRet;

        case WM_LBUTTONUP:
             ThumbMoving = 0;
             if (TimerDelay) { KillTimer(hWnd, 1); TimerDelay = 0; }
             ReleaseCapture();
             skUpdateWindow(hWnd, 0);
             break;

        case WM_SIZE:
             GetWindowRect(hParent, &rw);
             p.x = 0; p.y = 0; ClientToScreen(GetParent(hParent), &p);
             x = rw.left - p.x; y = rw.top - p.y;
             w = rw.right - rw.left; h = rw.bottom - rw.top;
             MoveWindow(hWnd, x, y, w, h, 0);
             GetClientRect(hParent, &rc);
       
             if (g_Child[skChild(hParent)].CtrlType == CTRL_COMBOLISTBOX) { nDelta = 1; } else { nDelta = 0; }
       
             hRgnClip = CreateRectRgn(0, 0, w, h + nDelta);
             hRgn = CreateRectRgn(rc.left + nDelta, rc.top + nDelta, rc.right + nDelta, rc.bottom + nDelta);
             CombineRgn(hRgnClip, hRgnClip, hRgn, RGN_DIFF);
             SetWindowRgn(hWnd, hRgnClip, 0);
             SetWindowRgn(hParent, hRgn, 0);
       
             if (nItem > -1) {
                UseSB = skCheckScrollBar(hParent);
                sbi.cbSize = sizeof(sbi);
                p.x = 0; p.y = 0; ClientToScreen(hWnd, &p);
                if ((UseSB == SCROLLBAR_VERT) || (UseSB == SCROLLBAR_BOTH)) {
                   GetScrollBarInfo(hParent, OBJID_VSCROLL, &sbi);
                   x = sbi.rcScrollBar.left - p.x;
                   y = sbi.rcScrollBar.top - p.y;
                   w = sbi.rcScrollBar.right - p.x - x;
                   h = sbi.rcScrollBar.bottom - p.y - y;
                   SetRect(&g_SI[nItem].rvu, x, y, x + sbi.dxyLineButton, y + sbi.dxyLineButton); // Vertical Up button
                   SetRect(&g_SI[nItem].rvt, x, y + sbi.xyThumbTop, x + sbi.dxyLineButton, y + sbi.xyThumbBottom); // Vertical Thumb button 
                   SetRect(&g_SI[nItem].rvd, x, y + h - sbi.dxyLineButton, x + sbi.dxyLineButton, y + h); // Vertical Down button
                }
                if ((UseSB == SCROLLBAR_HORZ) || (UseSB == SCROLLBAR_BOTH)) {
                   GetScrollBarInfo(hParent, OBJID_HSCROLL, &sbi);
                   x = sbi.rcScrollBar.left - p.x;
                   y = sbi.rcScrollBar.top - p.y;
                   w = sbi.rcScrollBar.right - p.x - x;
                   h = sbi.rcScrollBar.bottom - p.y - y;
                   SetRect(&g_SI[nItem].rhl, x, y, x + sbi.dxyLineButton, y + sbi.dxyLineButton); // Vertical Up button
                   SetRect(&g_SI[nItem].rht, x + sbi.xyThumbTop, y, x + sbi.xyThumbBottom, y + sbi.dxyLineButton); // Vertical Thumb button 
                   SetRect(&g_SI[nItem].rhr, x + w - sbi.dxyLineButton, y, x + w, y + sbi.dxyLineButton); // Vertical Down button
                }
             }
             return nRet;

        case WM_PRINT:
        case WM_PAINT:
        case WM_ERASEBKGND:
             if (uMsg == WM_PAINT) {
                hDCpaint = BeginPaint(hWnd, &ps); }
             else { // WM_PRINT
                hDCpaint = (HDC) wParam;
             }
             hDC = hDCpaint;

             UseSB = skCheckScrollBar(hParent);
             // GOSUB DetectState
             if (IsLButtonDown()) {
                 GetWindowRect(hWnd, &rw);
                 GetCursorPos(&p);
                 p.x -= rw.left; p.y -= rw.top;
                 
                 GetClientRect(hWnd, &rc);
                 if ((UseSB == SCROLLBAR_BOTH) && (p.x > rc.right - GetSystemMetrics(SM_CXVSCROLL) - 1) && (y > rc.bottom - GetSystemMetrics(SM_CYHSCROLL) - 1)) {
                     p.x = 0; p.y = 0; } // Do nothing
                 else {
                     if (p.x < rc.right - GetSystemMetrics(SM_CXVSCROLL)) {
                         // HORIZONTAL SCROLLBAR
                         if (PtInRect(&g_SI[nItem].rhl, p)) {      // Button Left
                            nState = 4; }
                         else if (PtInRect(&g_SI[nItem].rht, p)) { // Button Thumb
                            nState = 5; }
                         else if (PtInRect(&g_SI[nItem].rhr, p)) { // Button Right
                            nState = 6; }
                         else {                                    // Page
                            nState = 8; }
                         }
                     else {
                         // VERTICAL SCROLLBAR
                         if (PtInRect(&g_SI[nItem].rvu, p)) {      // Button Up
                            nState = 1; }
                         else if (PtInRect(&g_SI[nItem].rvt, p)) { // Button Thumb
                            nState = 2; }
                         else if (PtInRect(&g_SI[nItem].rvd, p)) { // Button Down
                            nState = 3; }
                         else {                                    // Page
                            nState = 7;
                         }
                     }
                 }
             }
             hMain = skPopupOwner(hWnd);

             sbi.cbSize =  sizeof(sbi);
             p.x = 0; p.y = 0; ClientToScreen(hWnd, &p);
       
             if ((UseSB == SCROLLBAR_VERT) || (UseSB == SCROLLBAR_BOTH)) {
       
                GetScrollBarInfo(hParent, OBJID_VSCROLL, &sbi);
                x = sbi.rcScrollBar.left - p.x;
                y = sbi.rcScrollBar.top - p.y;
                w = sbi.rcScrollBar.right - p.x - x;
                h = sbi.rcScrollBar.bottom - p.y - y;
       
                if (UseSB == SCROLLBAR_BOTH) { GetClientRect(hWnd, &rc); hH = rc.bottom - h; }
                if (uMsg == WM_PAINT) {
                   hDC = skOFFscreen(hDCpaint, w, h + hH, 1);
                   xX = x; yY = y; }
                else {
                   xX = 0; yY = 0;
                }
       
                GetWindowRect(hMain, &rw);
                ofX = sbi.rcScrollBar.left - rw.left; ofY = sbi.rcScrollBar.top - rw.top;
       
                if (g_Child[skChild(hParent)].CtrlType == CTRL_COMBOLISTBOX) {
                   nDelta = 1;
                   w = w - nDelta;
                   // Draw shadow border.
                   skDrawRect3D(hDC, 0, 0, x + w + 2, h + 2, skGetSysColor(SKCOLOR_EDITCOLORRECTUP), skGetSysColor(SKCOLOR_EDITCOLORRECTDOWN)); }
                else {
                   nDelta = 0;
                }
               
                skAlphaBlend(hDC, x - xX, y - yY, w, h, skGetHdcMemBmp(hMain), ofX, ofY, w, h);
       
                skPaintButton(hDC, 3, g_VertBar, x - xX, y - yY, w, h);
       
                SetRect(&g_SI[nItem].rvt, x, y + sbi.xyThumbTop, x + sbi.dxyLineButton, y + sbi.xyThumbBottom); // Vertical Thumb button 
                if (nState == 1) {
                    UseState = 2; }
                else {
                    UseState = 1;
                }
                skPaintButton(hDC, UseState, g_VertBar, g_SI[nItem].rvu.left - xX, g_SI[nItem].rvu.top - yY, g_SI[nItem].rvu.right - g_SI[nItem].rvu.left, g_SI[nItem].rvu.bottom - g_SI[nItem].rvu.top);
                    DrawPicto(hDC, 1, g_SI[nItem].rvu.left - xX, g_SI[nItem].rvu.top - yY, g_SI[nItem].rvu.right - g_SI[nItem].rvu.left, g_SI[nItem].rvu.bottom - g_SI[nItem].rvu.top);
                if (nState = 2) {
                    UseState = 5; }
                else {
                    UseState = 1;
                }
                skPaintButton(hDC, UseState, g_VertBar, g_SI[nItem].rvt.left - xX, g_SI[nItem].rvt.top - yY, g_SI[nItem].rvt.right - g_SI[nItem].rvt.left, g_SI[nItem].rvt.bottom - g_SI[nItem].rvt.top);
                    DrawPicto(hDC, 2, g_SI[nItem].rvt.left - xX, g_SI[nItem].rvt.top - yY, g_SI[nItem].rvt.right - g_SI[nItem].rvt.left, g_SI[nItem].rvt.bottom - g_SI[nItem].rvt.top);
                if (nState = 3) {
                    UseState = 2; }
                else {
                    UseState = 1;
                }
                skPaintButton(hDC, UseState, g_VertBar, g_SI[nItem].rvd.left - xX, g_SI[nItem].rvd.top - yY, g_SI[nItem].rvd.right - g_SI[nItem].rvd.left, g_SI[nItem].rvd.bottom - g_SI[nItem].rvd.top);
                    DrawPicto(hDC, 3, g_SI[nItem].rvd.left - xX, g_SI[nItem].rvd.top - yY, g_SI[nItem].rvd.right - g_SI[nItem].rvd.left, g_SI[nItem].rvd.bottom - g_SI[nItem].rvd.top);
                if (UseSB == SCROLLBAR_BOTH) { // Paint the right corner
                    skAlphaBlend(hDC, x - xX, y - yY + h, w, hH, skGetHdcMemBmp(hMain), ofX, ofY + h, w, hH);
                    skPaintButton(hDC, 3, g_VertBar, x - xX, y - yY + h, w, hH);
                }

                if (uMsg == WM_PAINT) { skOFFscreen(0, x, y, 0); }

             }
             if ((UseSB == SCROLLBAR_HORZ) || (UseSB == SCROLLBAR_BOTH)) {
       
                GetScrollBarInfo(hParent, OBJID_HSCROLL, &sbi);
                x = sbi.rcScrollBar.left - p.x;
                y = sbi.rcScrollBar.top - p.y;
                w = sbi.rcScrollBar.right - p.x - x;
                h = sbi.rcScrollBar.bottom - p.y - y;
       
                if (uMsg == WM_PAINT) {
                   hDC = skOFFscreen(hDCpaint, w, h, 1);
                   xX = x; yY = y; }
                else {
                   xX = 0; yY = 0;
                }
       
                GetWindowRect(hMain, &rw);
                ofX = sbi.rcScrollBar.left - rw.left; ofY = sbi.rcScrollBar.top - rw.top;
       
                skAlphaBlend(hDC, x - xX, y - yY, w, h, skGetHdcMemBmp(hMain), ofX, ofY, w, h);
       
                skPaintButton(hDC, 3, g_HorzBar, x - xX, y - yY, w, h);
       
                SetRect(&g_SI[nItem].rht, x + sbi.xyThumbTop, y, x + sbi.xyThumbBottom, y + sbi.dxyLineButton); // Vertical Thumb button 
       
                if (nState == 4) { UseState = 2; } else { UseState = 1; }
                skPaintButton(hDC, UseState, g_HorzBar, g_SI[nItem].rhl.left - xX, g_SI[nItem].rhl.top - yY, g_SI[nItem].rhl.right - g_SI[nItem].rhl.left, g_SI[nItem].rhl.bottom - g_SI[nItem].rhl.top);
                    DrawPicto(hDC, 4, g_SI[nItem].rhl.left - xX, g_SI[nItem].rhl.top - yY, g_SI[nItem].rhl.right - g_SI[nItem].rhl.left, g_SI[nItem].rhl.bottom - g_SI[nItem].rhl.top);
                if (nState == 5) { UseState = 5; } else { UseState = 1; }
                skPaintButton(hDC, UseState, g_HorzBar, g_SI[nItem].rht.left - xX, g_SI[nItem].rht.top - yY, g_SI[nItem].rht.right - g_SI[nItem].rht.left, g_SI[nItem].rht.bottom - g_SI[nItem].rht.top);
                    DrawPicto(hDC, 5, g_SI[nItem].rht.left - xX, g_SI[nItem].rht.top - yY, g_SI[nItem].rht.right - g_SI[nItem].rht.left, g_SI[nItem].rht.bottom - g_SI[nItem].rht.top);
                if (nState == 6) { UseState = 2; } else { UseState = 1; }
                skPaintButton(hDC, UseState, g_HorzBar, g_SI[nItem].rhr.left - xX, g_SI[nItem].rhr.top - yY, g_SI[nItem].rhr.right - g_SI[nItem].rhr.left, g_SI[nItem].rhr.bottom - g_SI[nItem].rhr.top);
                    DrawPicto(hDC, 6, g_SI[nItem].rhr.left - xX, g_SI[nItem].rhr.top - yY, g_SI[nItem].rhr.right - g_SI[nItem].rhr.left, g_SI[nItem].rhr.bottom - g_SI[nItem].rhr.top);

                if (uMsg == WM_PAINT) { skOFFscreen(0, x, y, 0); }

             }

             if (uMsg == WM_PAINT) {
                EndPaint(hWnd, &ps);
             }
             if (uMsg == WM_ERASEBKGND) {
                nRet = 1; }
             else {
                nRet = 0;
             }
             return nRet;

        case WM_DESTROY:
             if (TimerDelay) { KillTimer(hWnd, 1); TimerDelay = 0; }
             break;
        }
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}


Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Mike Lobanovsky on January 19, 2015, 01:37:31 AM
Quote
Tooks me years to figure how to handle them correctly
I realize and appreciate that to the fullest.

That was a lot of work but that was the only way to complement the other controls in your aero skinning engine. All your GUIs are real beauties. You've got a rare combination of talents as an artist and software developer. :)

I guess a similar implementation of scrollbar in my relatively simple project would be too much, since that scrolling functionality can be mimic'ed with a much simpler means like those three trackbars that I'm using to adjust the aero params. I can use a similar vertical trackbar to scroll the text area, and in this manner I'll be able to reuse the existing code though of course it should be improved to some extent in order to make dragging more secure in what regards the cursor's permissible positioning while the trackbar thumb (knob) is being dragged.

Thanks for your advice anyway. Negative is also a valid result, and your hard-earned experience saved me a lot of my time that would otherwise be spent on fruitless investigation of my own. :)
Title: Re: OxyScheme (Scheme Interpreter in O2)
Post by: Patrice Terrier on January 19, 2015, 01:56:07 AM
Quote
I can use a similar vertical trackbar to scroll the text area.
Absolutly ! that's the easiest way.

In my case i was forced to bite the bullet, because i was skinning "on the fly" the pre-existing controls.

...