Pelles C forum

C language => User contributions => Topic started by: henrin on September 05, 2015, 12:12:34 am

Title: SGL - win32 made simple!
Post by: henrin on September 05, 2015, 12:12:34 am
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.
Title: Re: SGL - win32 made simple!
Post by: jj2007 on September 05, 2015, 12:50:06 pm
Compliments, it works like a charm, in just 40 lines!

Code: [Select]
#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 ;
}
Title: Re: SGL - win32 made simple!
Post by: migf1 on September 06, 2015, 11:01:03 am
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.
Title: Re: SGL - win32 made simple!
Post by: henrin on October 19, 2015, 07:41:20 pm
Thank you jj2007 and migf1.
The story continues: here is the v1.1 version.

Some improvements in resizing and default values:
New features:

To remain in upload size limit, only the 32-bit sample executables are included.
You still have:

Next step : make it open source.
Title: Re: SGL - win32 made simple!
Post by: DD on November 05, 2015, 05:38:38 am
i've been using it for some tests.
thanks for the hard work!
Title: Re: SGL - win32 made simple!
Post by: henrin on January 17, 2016, 05:03:44 pm
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.
Title: Re: SGL - win32 made simple!
Post by: frankie on January 17, 2016, 09:35:14 pm
Good job!
Thanks for sharing.  :)
Title: Re: SGL - win32 made simple!
Post by: Bitbeisser on January 20, 2016, 02:49:31 am
Good job!
Thanks for sharing.  :)
+1

Ralf
Title: New release
Post by: henrin on October 10, 2016, 06:41:55 pm
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).
Title: Re: SGL - win32 made simple!
Post by: henrin on November 18, 2016, 11:51:33 pm
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).

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

Title: Re: SGL - win32 made simple!
Post by: jj2007 on November 19, 2016, 11:06:09 am
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);
Title: Re: SGL - win32 made simple!
Post by: henrin on November 19, 2016, 08:21:37 pm
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.
Title: Re: SGL - win32 made simple!
Post by: jj2007 on November 19, 2016, 09:17:42 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/).

Quote
Under 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  :)
Title: Re: SGL - win32 made simple!
Post by: frankie on November 20, 2016, 10:20:29 pm
Good job henrin  ;)
Title: Re: SGL - win32 made simple!
Post by: jj2007 on November 20, 2016, 11:16:13 pm
henrin,
did you have any luck with animated PNGs? Firefox (and others, I suppose) "plays" them just fine, but GdipImageGetFrameCount returns always one frame >:(
Title: Re: SGL - win32 made simple!
Post by: henrin on November 21, 2016, 09:34:50 am
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.
Title: Re: SGL - win32 made simple!
Post by: TimoVJL on November 21, 2016, 09:58:35 am
https://en.wikipedia.org/wiki/APNG
Title: Re: SGL - win32 made simple!
Post by: jj2007 on November 21, 2016, 01:21:28 pm
I 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.
Title: Re: SGL - win32 made simple!
Post by: henrin on November 21, 2016, 05:22:32 pm
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.
Title: Re: SGL - win32 made simple!
Post by: jj2007 on November 21, 2016, 05:54:35 pm
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.
Title: Re: SGL - win32 made simple!
Post by: TimoVJL on November 21, 2016, 06:02:35 pm
MultiTIFF, remind me a FAX
This example make 3 pages TIFF.
Code: [Select]
#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 = &parameterValue;
// 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);
}
Title: Re: SGL - win32 made simple!
Post by: cnoob on September 06, 2018, 12:58:59 pm
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  :-\
Title: Re: SGL - win32 made simple!
Post by: henrik on September 20, 2018, 08:42:40 am
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)
Title: Re: SGL - win32 made simple!
Post by: TimoVJL on September 20, 2018, 10:48:43 am
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.
Title: Re: SGL - win32 made simple!
Post by: henrik on September 20, 2018, 03:57:00 pm
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
Title: Re: SGL - win32 made simple!
Post by: henrik on September 21, 2018, 09:14:27 am
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
Title: Re: SGL - win32 made simple!
Post by: cnoob on September 23, 2018, 03:27:05 am
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
Title: Re: SGL - win32 made simple!
Post by: cnoob on October 12, 2018, 08:03:44 am
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  :(
Title: Re: SGL - win32 made simple!
Post by: cnoob on October 12, 2018, 12:56:12 pm
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
Title: Re: SGL - win32 made simple!
Post by: cnoob on October 13, 2018, 04:51:21 pm
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.
Title: Re: SGL - win32 made simple!
Post by: henrik on November 24, 2018, 09:07:40 pm
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:
The updated development kit (*.h, *.lib and *.chm) and the samples are still there http://perso.numericable.fr/hserindat/sgl/.

Attached files:

Title: Re: SGL - win32 made simple!
Post by: d3dx on February 22, 2019, 11:02:40 pm
–°ool thing! :)

Thank you very much, Henri!
Title: Re: SGL - win32 made simple!
Post by: 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.
Title: Re: SGL - win32 made simple!
Post by: cnoob on May 14, 2019, 06:32:59 am
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. :'(