I have read many posts looking for easy win32 gui programming.
Not founding a good solution, and considering Win32 is almost
fantastic, I decided to fill the gap.
Here is SGL - Features:
- easy Win32 programming (better OOP)
- grid layout with alignmment and padding
- scalable GUI
The kit contains:
- help file (sgl.chm)
- dev kit: x.lib and x.h
- sample programs (source, project and exe files)
The available objects are:
- buttons
- table (data grid)
- image
- edit
- graph
- popups
The mandatoty Hello progam is just 12 lines:
#include "sgl.h"
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPInst, PSTR cmdLine, int cmdShow)
{
SGL_Init(hInst, NULL) ;
HWND panel = SGL_New(0, SGL_PANEL, 0, "SGL", -1, -1) ;
HWND btn = SGL_New(panel, SGL_CTRL_BUTTON, 0, "Hello!", 0, 0) ;
SGL_Layout(panel) ;
SGL_VisibleSet(panel, 1) ;
SGL_Run() ;
SGL_Exit() ;
return 0 ;
}
More samples in the downloadable kit.
Compliments, it works like a charm, in just 40 lines!
#include "sgl.h" // all sgl*.h must be in include folder (includes <stdio.h>)
#pragma comment(linker, "sgl32.lib" ) // sgl32.lib must be in lib folder
#pragma warn(disable:2216) // retval never used
#pragma warn(disable:2018) // Undeclared function 'sprintf'
#pragma warn(disable:2118) // para not referenced
#pragma comment(linker, "/Subsystem:Windows" )
#pragma warn(disable:2215) // conversion ... loss of data
#define BTN_NB 6
#define TEXT_LEN 10
int buttonCB(HWND hwnd, UINT event, WPARAM wParm, LPARAM lParm) {
if (event == WM_LBUTTONUP) {
RECT rect ; // rectangle for the edit box
GetClientRect(hwnd, &rect) ;
MapWindowPoints(hwnd, NULL, (POINT*) &rect, 2) ;
char* text ; // edited text
SGL_CallbackDataGet(hwnd, (void*) &text) ;
SGL_PopupEdit(hwnd, &rect, ES_CENTER, SGL_WHITE,
text, TEXT_LEN, NULL, NULL) ;
return 1 ;
}
return 0 ;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
static char btnText[BTN_NB][TEXT_LEN] ; // buttons' text
SGL_Init(hInstance, NULL) ;
HWND topPanel = SGL_New(0, SGL_PANEL, 0, "BUTTONS", 90, 30) ;
for (int i = 0 ; i < BTN_NB ; i++) { // create each button
sprintf(btnText[i], "Button #%d", i + 1) ;
HWND btn = SGL_New(topPanel, SGL_CTRL_BUTTON, 0, btnText[i], 0, i) ;
SGL_CallbackFunctionSet(btn, buttonCB) ;
SGL_CallbackDataSet(btn, (void*) &btnText[i]) ;
}
SGL_Layout(topPanel) ;
SGL_VisibleSet(topPanel, 1) ;
SGL_Run() ;
SGL_Exit() ;
return 0 ;
}
Although I've personally settled in GTK+ when it comes to GUI programming with C, I want to congratulate you for this effort!
I went through SGL docs, though in a hurry. Was impressed and I believe SGL deserves to go open-source, ideally in its own git repo. If not, it may be a good idea to also provide ming32 and/or mingw-w64 pre-compiled binaries.
Thanks for sharing and once again congrats for the effort so far.
Thank you jj2007 and migf1.
The story continues: here is the v1.1 version.
Some improvements in resizing and default values:
- Panel sizing is now possible.
- SGL fonts are now strictly linked to the desktop menu font.
- The separator object is now spanned to its parent border.
New features:
- New macros for testing the mouse buttons.
- New tool for Automatic resizing.
- New object OpenGL
To remain in upload size limit, only the 32-bit sample executables are included.
You still have:
- the help file
- the .h and the .lib (32 & 64-bit) files
- the samples: source, project files, .exe files
Next step : make it open source.
i've been using it for some tests.
thanks for the hard work!
A new release and the source code
The 1.2 release mainly adds a date-time popup. Two sample are provided:
- 2 date buttons for a round trip ticket,
- editing a date in a table (data grid).
One feature has been lost: the backgroung color for user editing is white and cannot be changed.
I have changed publishing:
- the development kit (*.h, *.lib and *.chm) and the samples are now there http://perso.numericable.fr/hserindat/sgl/ (http://perso.numericable.fr/hserindat/sgl/),
- the source code can now be downloaded here (also includes the samples).
Terms of use:
SGL is freeware for any use: personal, commercial, etc. No registration is required to download it, and you can use it anonymously.
SGL can be freely distributed, but it can not be sold.
SGL is provided 'as-is', without any expressed or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.
Good job!
Thanks for sharing. :)
SGL 1.3 is here with new features:
- Temporary font loading.
- New tools for reading and writing in a configuration file.
other improvements and a new sample (custom message box).
The development kit (*.h, *.lib and *.chm) and the samples are here http://perso.numericable.fr/hserindat/sgl/v_1.3/release_sgldevkit.7z (http://perso.numericable.fr/hserindat/sgl/v_1.3/release_sgldevkit.7z),
The source code can now be downloaded here (also includes the samples).
A light update.SGL provided native scrolling under foreground windows [MouseWheelRouting].
As well as Windows10 now. This required some adjustment which accidentally broke the compatibility with Windows XP.
That is repaired with the 1.3.1 version.
The previous release was not exciting; the goodies were not emphazed enough.
Here is a nice one: a message box, in less than 200 lines (exe and ini files attached).
- Window size and position setting and saving for panels and buttons.
- Setting and saving of custom colors.
- Custom popup.
- Automatic size adjustments.
- Version info (right click on the .exe file: properties / details).
- Native scrolling under foreground window as mentionned above.
The development kit (*.h, *.lib and *.chm) and the samples are here http://perso.numericable.fr/hserindat/sgl/v_1.3.1/release_sgldevkit.7z,
The source code can be downloaded here (attached file which also includes the source code of the samples).
Very nice! I had a look at the animated GIF example. How are you doing that?
These seem to be the relevant functions, but what do they use under the hood? Just curious...
SGL_ImagePlay(image, 100);
SGL_ImageFrameIndexSet(image, i);
Animated works for GIF, and for multiframe TIFF also! (win7 and above).
The relevant SGL functions are described in the help file : CONTROL OBJECTS / IMAGE (inside http://perso.numericable.fr/hserindat/sgl/v_1.3.1/release_sgldevkit.7z (http://perso.numericable.fr/hserindat/sgl/v_1.3.1/release_sgldevkit.7z)).
Under the hood, there is GDI+ and an animation thread. Unfortunately, at the time of development I did not find a very good gdi+ header. The header I have found in T-Clock (by Frankie) seems much cleaner.
The code for the image object is :
- sgl_gdiplus_.h (GDI+ header)
- sgl_image_.h (private header)
- sgl_image.c (code)
- sgl_image.h (public header)
and is attached to this post.
Quote from: henrin on November 19, 2016, 08:21:37 PM
Animated works for GIF, and for multiframe TIFF also! (win7 and above).
I tried to find animated TIFF images for testing but
no luck so far I found only two here (http://www.nightprogrammer.org/development/multipage-tiff-example-download-test-image-file/).
QuoteUnder the hood, there is GDI+
In the meantime, I rolled my own, see here (http://masm32.com/board/index.php?topic=5810.0). But thanks for inspiring me :)
Good job henrin ;)
henrin,
did you have any luck with animated PNGs? Firefox (and others, I suppose) "plays" them just fine, but GdipImageGetFrameCount returns always one frame >:(
Hello jj2007,
I never heard about animated PNGs. This format does not seem to be widely accepted, and I am not surprised that GDI+ ignore it.
To test multiframe TIFF images, I used the attached image (probably the only one I have found, and I do not remember where!).
In a previous post I did not attach correctly the message box sample. Here it is.
https://en.wikipedia.org/wiki/APNG
Quote from: henrin on November 21, 2016, 09:34:50 AMI do not remember where
http://www.nightprogrammer.org/development/multipage-tiff-example-download-test-image-file/
There are two examples, and indeed I didn't find any others on the wide world web :(
But they both work fine. In contrast to the GIFs, their PropertyTagFrameDelay is not set, though.
APNG is a different story indeed, not supported by Gdi+, and while it would be theoretically possible to pick a frame from an APNG, it would be a lot of work with a badly documented format.
Make your own multiframe TIFF images!
I just remember few years ago ( today its my birthday 8) ) I created multiframe images, here is how :
- use ACDSee (my sersion is ACDSee Pro 7)
- select several images
- menu batch image conversion
The last option before conversion starts is for multiframe.
TIP : sample_image64/32.exe does not erase the panel before each image.
Results may be unpleasant if all frames don't have the same size.
It is possible to view multiframe images with ACDSee, as well as with FastStome Image Viewer.
Happy birthday then :)
Re roll your own: Not worth the effort for TIFFs. It's an exotic format anyway, so I guess animated GIFs is enough for 99% of all users. APNG may be the future. I wonder if they have much better compression than GIF, though.
MultiTIFF, remind me a FAX
This example make 3 pages TIFF.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//#include "GdiPlusFlat.h"
#pragma comment(linker, "-subsystem:windows")
#pragma comment(lib, "gdiplus.lib")
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms534041(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/ms533839(v=vs.85).aspx
typedef int GpStatus;
#define WINGDIPAPI __stdcall
#define GDIPCONST const
typedef struct
{
UINT32 GdiplusVersion ;
void* DebugEventCallback ;
BOOL SuppressBackgroundThread ;
BOOL SuppressExternalCodecs ;
} GDIPLUSSTARTUPINPUT ;
/*
typedef int (_stdcall *NotificationHookProc)(ULONG_PTR *token);
typedef VOID (_stdcall *NotificationUnhookProc)(ULONG_PTR token);
*/
typedef struct
{
void* NotificationHook; //NotificationHookProc NotificationHook;
void* NotificationUnhook; //NotificationUnhookProc NotificationUnhook;
} GDIPLUSSTARTUPOUTPUT ;
typedef struct EncoderParameter {
GUID Guid;
ULONG NumberOfValues;
ULONG Type;
VOID *Value;
} EncoderParameter;
typedef struct EncoderParameters {
UINT Count;
EncoderParameter Parameter[1];
} EncoderParameters;
typedef enum EncoderParameterValueType {
EncoderParameterValueTypeByte = 1,
EncoderParameterValueTypeASCII = 2,
EncoderParameterValueTypeShort = 3,
EncoderParameterValueTypeLong = 4,
EncoderParameterValueTypeRational = 5,
EncoderParameterValueTypeLongRange = 6,
EncoderParameterValueTypeUndefined = 7,
EncoderParameterValueTypeRationalRange = 8,
EncoderParameterValueTypePointer = 9
} EncoderParameterValueType;
typedef enum EncoderValue {
EncoderValueColorTypeCMYK = 0,
EncoderValueColorTypeYCCK = 1,
EncoderValueCompressionLZW = 2,
EncoderValueCompressionCCITT3 = 3,
EncoderValueCompressionCCITT4 = 4,
EncoderValueCompressionRle = 5,
EncoderValueCompressionNone = 6,
EncoderValueScanMethodInterlaced = 7,
EncoderValueScanMethodNonInterlaced = 8,
EncoderValueVersionGif87 = 9,
EncoderValueVersionGif89 = 10,
EncoderValueRenderProgressive = 11,
EncoderValueRenderNonProgressive = 12,
EncoderValueTransformRotate90 = 13,
EncoderValueTransformRotate180 = 14,
EncoderValueTransformRotate270 = 15,
EncoderValueTransformFlipHorizontal = 16,
EncoderValueTransformFlipVertical = 17,
EncoderValueMultiFrame = 18,
EncoderValueLastFrame = 19,
EncoderValueFlush = 20,
EncoderValueFrameDimensionTime = 21,
EncoderValueFrameDimensionResolution = 22,
EncoderValueFrameDimensionPage = 23
} EncoderValue;
int __stdcall GdiplusStartup(ULONG_PTR*, const GDIPLUSSTARTUPINPUT*, GDIPLUSSTARTUPOUTPUT*) ;
VOID __stdcall GdiplusShutdown(ULONG_PTR) ;
typedef void GpImage;
int __stdcall GdipLoadImageFromFile(WCHAR* filename, GpImage **image);
int __stdcall GdipSaveImageToFile(GpImage *image, WCHAR* filename, GDIPCONST CLSID* clsidEncoder, void*);
// EncoderParameters* encoderParams);
int __stdcall GdipSaveAdd(GpImage*,GDIPCONST EncoderParameters*);
int __stdcall GdipSaveAddImage(GpImage*,GpImage*,GDIPCONST EncoderParameters*);
int __stdcall GdipDisposeImage(GpImage*);
GDIPLUSSTARTUPINPUT gdiplusStartupInput = { 1, NULL, FALSE, FALSE } ;
ULONG_PTR gdiplusToken;
const CLSID CLSID_image_bmp = {0x557CF400,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_jpeg = {0x557CF401,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_gif = {0x557CF402,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_tiff = {0x557CF405,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_png = {0x557CF406,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_ico = {0x557CF407,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
//292266fc-ac40-47bf-8cfc-a85b89a655de
const CLSID EncoderSaveFlag = {0x292266FC,0xAC40,0x47BF,0x8C,0xFC,0xA8,0x5B,0x89,0xA6,0x55,0xDE};
void __cdecl WinMainCRTStartup(void)
{
GpStatus status;
GpImage *image = NULL;
EncoderParameters encoderParameters;
ULONG parameterValue;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
encoderParameters.Count = 1;
// Initialize the one EncoderParameter object.
encoderParameters.Parameter[0].Guid = EncoderSaveFlag;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;
encoderParameters.Parameter[0].Value = ¶meterValue;
// Load the first page (frame).
status = GdipLoadImageFromFile(L"testimg.bmp", (GpImage **)&image);
if (status == 0) {
GpImage *image2 = NULL;
// Save the first page (frame).
parameterValue = EncoderValueMultiFrame;
status = GdipSaveImageToFile(image, L"test1.tif", &CLSID_image_tiff, &encoderParameters);
// Save the second page (frame).
status = GdipLoadImageFromFile(L"testimg.bmp", (GpImage **)&image2);
parameterValue = EncoderValueFrameDimensionPage;
status = GdipSaveAddImage(image, image2, &encoderParameters);
GdipDisposeImage(image2);
// Save the third page (frame).
status = GdipLoadImageFromFile(L"testimg.bmp", (GpImage **)&image2);
parameterValue = EncoderValueFrameDimensionPage;
status = GdipSaveAddImage(image, image2, &encoderParameters);
GdipDisposeImage(image2);
// Close the multiframe file.
parameterValue = EncoderValueFlush;
status = GdipSaveAdd(image, &encoderParameters);
GdipDisposeImage(image);
}
GdiplusShutdown(gdiplusToken);
ExitProcess(0);
}
Is this project dead? I download and tried Pelles C 9 give me many errors about missing symbol. I link sgl64.lib correctly though. When I opened the ppj file with notepad it said Pelles C 7.00, is it the reason why it failed? If you still there, please update to latest Pelles C version or consider release the source code, I found only header and a precompiler sgl32/64.lib but no c source file. Thanks :-\
Hello to every body.
That's true, I was retired for few months, but now back for SGL with a new name (henrik instead of henrin).
The previous version was released with my post of November 19, 2016, and a new version is available here.
New for version 1.3.2 :
- The default font is now the message font (instead of menu font).
- Documentation: minor updates.
The project is still with PellesC 8.00 and the ppj file is :
PROJECT FILE generated by "Pelles C for Windows, version 8.00".
# WARNING! DO NOT EDIT THIS FILE.
#
POC_PROJECT_VERSION = 7.00
When when switching between 32-bit and 64-bit projects in the same directory, you should :
- update all dependencies
- rebuild the project
You can find the development kit here http://perso.numericable.fr/hserindat/sgl/ (http://perso.numericable.fr/hserindat/sgl/) with documentation and samples.
The source code is available to registered members of the PellesC forum.
Another example of use is PUKABO, a simple and stupid backup program http://perso.numericable.fr/hserindat/pukabo/index.html (http://perso.numericable.fr/hserindat/pukabo/index.html)
Thanks Henri.
With 32-bit library have to use a __cdecl calling convention.
For PellesC 9, the libraries have to recompile, as without it:
POLINK: error: Unresolved external symbol '___get_touppertab' - referenced from 'sgl32.lib(sgl_tools.obj)'.
POLINK: error: Unresolved external symbol '__get_touppertab' - referenced from 'sgl64.lib(sgl_tools.obj)'.
EDIT: sgl project files for V9, using src sub-folder for sources.
OK TimoVJLand cnoob, I'll switch to PellesC 9and look at this.
The calling conventions are OK and I did not get these errors with PellesC 8
The problem appears with PellesC 9. It upgrades the project file (sgl64.ppj) and sgl64.lib cannot be built ???
I have rebuilt the project from scratch and it works nice :
- sgl64.lib is built
- no unresolved symbol when building the sample programs with it.
I'll investigate what is the reason and then provide the full package.
For now, the attachement the sgl64.lib for PellesC9
Hihi, I've switched to Pelles C 7.0 because I saw 7.00 in the project file. It's foolish. But it worked well so far ;D
henrik, could you provide a version of SGL for MinGW? I know this forum is for Pelles but I'm using libCello which doesn't work with Pelles now :(
hi henrik, your code is portable. after a little patch I've successfully port it to MinGW to use with LibCello. If any of you want, i will publish my modifed version of henrik's sgl src :D
Henri's code already portable because it's just a thin wrapper for WinAPI. Any compiler has mature enough WinAPI support could compile SGL.
This is what I've done to compile SGL under MinGW64 i686-sjlj 8.1.0 (notice: sjlj, dwarf can't throw exception on non-dwarf aware dll like of Windows):
First, replace _stdcall with __stdcall. Pelles compiles _stdcall just fine but MinGW doesn't. I #define _stdcall __stdcall.
Second, #pragma comment is not understood by MinGW so I've to check each pragma to know which lib SGL depends on, on MinGW there's something like -Wl import bla bla for auto import needed lib but I don't trust it. So far SGL needs: advapi32, gdi32, msimg32, gdiplus, shlwapi, opengl32, glu32 and comctl32.
Third, SGL seemed to support only Windows >= 7. On sgl_debug.c MinGW will throw error WM_GESTURE not defined. It's because MinGW still target Windows ver 0x502 (very old). You've to edit sdkddkver.h and _mingw.h to change all on the define of win ver and nt to of Win7 0x601 (my computer so far, I didn't try Win8, Win10...).
Now it happy compiles and provide libSGL.a (just like your .lib), libSGL.dll and libSGL.def.
All of the example recompiled with MinGW worked except sample_text will crash that I didn't know why. It's run ok with Pelles C's compiled version.
Hi cnoob
I do not know why there was a problem with only one function of the standard library (ctype.c: toupper()).
So I reworked sgl_tools.c:SGL_ProfileIntGet(), the only function which uses toupper().
The result:
- toupper() is no more used and the generated lib is compatible with PellesC versions 8 and 9 (64-bit version).
- SGL_ProfileIntGet() has been updated for error handling.
The updated development kit (*.h, *.lib and *.chm) and the samples are still there http://perso.numericable.fr/hserindat/sgl/.
Attached files:
- sgl.chm: the updated documentation
- the source files: release_sglsrckit.7z
- the only modified source: sgl_tools.c
Сool thing! :)
Thank you very much, Henri!
The edit popup appeared to have a bug.
The first parameter of the callback function (virtKey) should indicate what is the user action which triggered the callback function. In some circumstances, it is VK_RETURN instead of VK_ESCAPE. This has been corrected in the 1.3.4 release.
The updated development kit (*.h, *.lib and *.chm) and the samples are still there http://perso.numericable.fr/hserindat/sgl/ (http://perso.numericable.fr/hserindat/sgl/).
Source code and documentation are attached to this post.
Sorry Henri for my many previous post. I have a bit trouble of reconsidering what I really like to do. I deleted them all.
Thank you for this library, it really helps me with creating small apps for fun. But I decided I was not fit to be a programmer so I will quit. Hope you will continue to develop this library to ease newbies to Win32 C programming easier to make Gui. Bye. :'(
Quote from: henrik on March 20, 2019, 11:48:20 AM
The edit popup appeared to have a bug.
The first parameter of the callback function (virtKey) should indicate what is the user action which triggered the callback function. In some circumstances, it is VK_RETURN instead of VK_ESCAPE. This has been corrected in the 1.3.4 release.
The updated development kit (*.h, *.lib and *.chm) and the samples are still there http://perso.numericable.fr/hserindat/sgl/ (http://perso.numericable.fr/hserindat/sgl/).
Source code and documentation are attached to this post.
Do you still develop this software?
Here is my codeblocks project and so could find my .def file inside Debug/bin folder. I also attached a test application linked with sgl.dll.
Thanks cnoob and opaque for your help.
A new version is here 1.3.5.
What is new:
- bug corrected in SGL_Error (!!!)
- kit distribution have evolved - see below
- minor update of the documentation
The distribution now consists of:
- the documentation (chm file)
- the development kit with a LIB runtime
- the development kit with a DLL runtime
- the source files
The samples (sources and exe files[/li][/list]) are too big to be attached to this post. You can find them on the SGL home page http://perso.numericable.fr/hserindat/sgl/index.html (http://perso.numericable.fr/hserindat/sgl/index.html)
Hi. Is this library still in development? I go to this forum from the FreeBASIC binding of this library here:
https://github.com/ruanjiaxing/SGL-FreeBASIC
The developer's account now is a guest so it seems he's not there for a long time.