phibermon
02-10-2010, 01:05 PM
Hi peeps, bit of an update for you, I've now started work on the visual side of the window/widget manager JUI. This is a re-design/re-write of my old VFA Window manager.
I've included screen shots of both the old VFA (craft2y.jpg) and the new JUI (CC_EARLY.JPG) so you can see where it currently stands in terms of matching the features of VFA.
VFA was a single threaded, immediate mode GUI with no message sub system (everything was triggered in events filtering down through the windows/widgets). This worked but was quite slow and the design was around 20 years out of date.
JUI is a multi-threaded, soon to be non-immediate, message driven window manager. Every single window and widget runs in it's own thread, able to deploy messages directly to any other component, including it's parent, in a lock free manner.
Because each widget runs in it's own thread as opposed to only a window having a thread in conventional desktop OS's, it allows for a nice trick: E.g. you can write some code that looped to infinity and place it in the onclick event of a button. The button will lock but every other widget and window is still functional.
The only issue with this design is thread overhead. if you have 100 widgets, you have 100 threads. This can become a problem as you move to several hundred widgets due to the memory allocation of each thread within the OS, basically your limited to around 2000 threads under posix systems, around 600 on Windows systems.
Here is an example unit for creating a window, widgets assigning callbacks etc
(Initialization of the Window manager and various other supporting functions is trivial so I won't display here)
unit cc_guimain;
{$mode objfpc}{$H+}
{$i jui.inc}
{$i pin.inc}
{$i cc.inc}
interface
uses
Classes, sysutils, sdl, u_gl,
j2d, j2d_poly, j2d_polygroup, j2d_tspline,
jui_const, jui_log, jui_screen, jui_textureman, jui_font,
jui_mouse, jui_cursor,
jui_global, jui_message, jui_messenger, jui_keyboard,
jui_lockable, jui_theme, jui_element, jui_window,
jui_windowman, jui_widget, jui_basetypes, jui_titlebar, jui_button,
jui_colourwheel, jui_editbox, jui_listview, jui_scrollbar,
pin_log, pin_lockable, pin_message, pin_messenger, pin_tcp,
cc_global, cc_gamestate;
type
TCCGUIMain = class
private
WindowMan : TJUIWindowMan;
public
Window : TJUIWindow;
TitleBar : TJUITitleBar;
StartServerButton : TJUIButton;
StartClientButton : TJUIButton;
EditBox : TJUIEditBox;
ListView : TJUIListView;
constructor create(AWindowMan : TJUIWindowMan);
destructor destroy;override;
procedure StartServerClick(ButtonMessage : TMsgMouseButton);
procedure StartClientClick(ButtonMessage : TMsgMouseButton);
end;
implementation
constructor TCCGUIMain.create(AWindowMan : TJUIWindowMan);
var
TempButton : TJUIButton;
begin
WindowMan := AWindowMan;
Window := WindowMan.CreateWindow;
Window.LocalRect := J2DRect(10,10,360,360);
Window.Caption := 'GUIMain - Testing Widgets';
TJUIWidget(TitleBar) := Window.CreateWidget(TJUITitleBar);
TitleBar.LocalRect := J2DRect(0,0,window.width,19);
Titlebar.Caption := 'GUIMain';
TJUIWidget(StartServerButton) := Window.CreateWidget(TJUIButton);
StartServerButton.LocalRect := J2DRect(5,25,80,45);
StartServerButton.Caption := 'Start Server';
StartServerButton.OnMouseClick := @StartServerClick;
TJUIWidget(StartClientButton) := Window.CreateWidget(TJUIButton);
StartClientButton.LocalRect := J2DRect(95,25,170,45);
StartClientButton.Caption := 'Start Client';
StartClientButton.OnMouseClick := @StartClientClick;
TJUIWidget(EditBox) := Window.CreateWidget(TJUIEditBox);
EditBox.LocalRect := J2DRect(180,25,290,41);
TJUIWidget(ListView) := Window.CreateWidget(TJUIListView);
ListView.LocalRect := J2DRect(5,55,290,305);
ListView.Anchor.Right := true;
listview.anchor.bottom := true;
listview.Columns[0].Caption := 'I love';
listview.AddColumn('Fish');
listview.AddColumn('Fingers');
listview.AddItem('It''s all good');
listview.Items[ListView.NumItems-1].SubItems[0].caption := 'This Is A SubItem';
end;
destructor TCCGUIMain.destroy;
begin
inherited;
end;
procedure TCCGUIMain.StartServerClick(ButtonMessage : TMsgMouseButton);
begin
if assigned(CCGlobal.PINServer) then
begin
CCGlobal.PINServer.OutBoundRelay := nil;
freeandnil(CCGlobal.ServerState);
freeandnil(CCGlobal.PINServer);
end else
begin
CCGlobal.PINServer := TPINServer.Create('0.0.0.0',6969);
CCGlobal.ServerState := TCCServerState.create;
CCGlobal.ServerState.OutBoundRelay := CCGlobal.PINServer;
CCGlobal.PINServer.OutBoundRelay := CCGlobal.ServerState;
CCGlobal.PINServer.Listen;
end;
end;
procedure TCCGUIMain.StartClientClick(ButtonMessage : TMsgMouseButton);
begin
if assigned(CCGlobal.PINClient) then
begin
CCGlobal.PINClient.OutBoundRelay := nil;
freeandnil(CCGlobal.ClientState);
freeandnil(CCGlobal.PINClient);
end else
begin
CCGlobal.PINClient := TPINClient.Create('192.168.0.1',6969);
CCGlobal.ClientState := TCCClientState.create;
CCGlobal.ClientState.OutBoundRelay := CCGlobal.PINClient;
CCGlobal.PINClient.OutBoundRelay := CCGlobal.ClientState;
CCGlobal.PINClient.Connect;
end;
end;
end.
So yes, I shall be releasing this at some point but I'm looking for another developer to help me with the workload. There's still a number of widgets I need to re-code and I may need help on moving to a faster VBO rendering method (need new font units, is GLViewPort depreciated? EDIT : GLViewPort is *not* depreciated :) )
The old VFA is usable in much the same manner, but the design stinks. if you really want it, let me know.
and on a side note I've nearly finished PIN and I'm going to wrap up my hardware skinning lib from P3D, in my opinion the most modern skinning implementation in delphi (EDIT:FreePascal/Lazarus for me personally, all the way :) ) that I've seen so far, hence why I want to give it to the community.
Peace.
I've included screen shots of both the old VFA (craft2y.jpg) and the new JUI (CC_EARLY.JPG) so you can see where it currently stands in terms of matching the features of VFA.
VFA was a single threaded, immediate mode GUI with no message sub system (everything was triggered in events filtering down through the windows/widgets). This worked but was quite slow and the design was around 20 years out of date.
JUI is a multi-threaded, soon to be non-immediate, message driven window manager. Every single window and widget runs in it's own thread, able to deploy messages directly to any other component, including it's parent, in a lock free manner.
Because each widget runs in it's own thread as opposed to only a window having a thread in conventional desktop OS's, it allows for a nice trick: E.g. you can write some code that looped to infinity and place it in the onclick event of a button. The button will lock but every other widget and window is still functional.
The only issue with this design is thread overhead. if you have 100 widgets, you have 100 threads. This can become a problem as you move to several hundred widgets due to the memory allocation of each thread within the OS, basically your limited to around 2000 threads under posix systems, around 600 on Windows systems.
Here is an example unit for creating a window, widgets assigning callbacks etc
(Initialization of the Window manager and various other supporting functions is trivial so I won't display here)
unit cc_guimain;
{$mode objfpc}{$H+}
{$i jui.inc}
{$i pin.inc}
{$i cc.inc}
interface
uses
Classes, sysutils, sdl, u_gl,
j2d, j2d_poly, j2d_polygroup, j2d_tspline,
jui_const, jui_log, jui_screen, jui_textureman, jui_font,
jui_mouse, jui_cursor,
jui_global, jui_message, jui_messenger, jui_keyboard,
jui_lockable, jui_theme, jui_element, jui_window,
jui_windowman, jui_widget, jui_basetypes, jui_titlebar, jui_button,
jui_colourwheel, jui_editbox, jui_listview, jui_scrollbar,
pin_log, pin_lockable, pin_message, pin_messenger, pin_tcp,
cc_global, cc_gamestate;
type
TCCGUIMain = class
private
WindowMan : TJUIWindowMan;
public
Window : TJUIWindow;
TitleBar : TJUITitleBar;
StartServerButton : TJUIButton;
StartClientButton : TJUIButton;
EditBox : TJUIEditBox;
ListView : TJUIListView;
constructor create(AWindowMan : TJUIWindowMan);
destructor destroy;override;
procedure StartServerClick(ButtonMessage : TMsgMouseButton);
procedure StartClientClick(ButtonMessage : TMsgMouseButton);
end;
implementation
constructor TCCGUIMain.create(AWindowMan : TJUIWindowMan);
var
TempButton : TJUIButton;
begin
WindowMan := AWindowMan;
Window := WindowMan.CreateWindow;
Window.LocalRect := J2DRect(10,10,360,360);
Window.Caption := 'GUIMain - Testing Widgets';
TJUIWidget(TitleBar) := Window.CreateWidget(TJUITitleBar);
TitleBar.LocalRect := J2DRect(0,0,window.width,19);
Titlebar.Caption := 'GUIMain';
TJUIWidget(StartServerButton) := Window.CreateWidget(TJUIButton);
StartServerButton.LocalRect := J2DRect(5,25,80,45);
StartServerButton.Caption := 'Start Server';
StartServerButton.OnMouseClick := @StartServerClick;
TJUIWidget(StartClientButton) := Window.CreateWidget(TJUIButton);
StartClientButton.LocalRect := J2DRect(95,25,170,45);
StartClientButton.Caption := 'Start Client';
StartClientButton.OnMouseClick := @StartClientClick;
TJUIWidget(EditBox) := Window.CreateWidget(TJUIEditBox);
EditBox.LocalRect := J2DRect(180,25,290,41);
TJUIWidget(ListView) := Window.CreateWidget(TJUIListView);
ListView.LocalRect := J2DRect(5,55,290,305);
ListView.Anchor.Right := true;
listview.anchor.bottom := true;
listview.Columns[0].Caption := 'I love';
listview.AddColumn('Fish');
listview.AddColumn('Fingers');
listview.AddItem('It''s all good');
listview.Items[ListView.NumItems-1].SubItems[0].caption := 'This Is A SubItem';
end;
destructor TCCGUIMain.destroy;
begin
inherited;
end;
procedure TCCGUIMain.StartServerClick(ButtonMessage : TMsgMouseButton);
begin
if assigned(CCGlobal.PINServer) then
begin
CCGlobal.PINServer.OutBoundRelay := nil;
freeandnil(CCGlobal.ServerState);
freeandnil(CCGlobal.PINServer);
end else
begin
CCGlobal.PINServer := TPINServer.Create('0.0.0.0',6969);
CCGlobal.ServerState := TCCServerState.create;
CCGlobal.ServerState.OutBoundRelay := CCGlobal.PINServer;
CCGlobal.PINServer.OutBoundRelay := CCGlobal.ServerState;
CCGlobal.PINServer.Listen;
end;
end;
procedure TCCGUIMain.StartClientClick(ButtonMessage : TMsgMouseButton);
begin
if assigned(CCGlobal.PINClient) then
begin
CCGlobal.PINClient.OutBoundRelay := nil;
freeandnil(CCGlobal.ClientState);
freeandnil(CCGlobal.PINClient);
end else
begin
CCGlobal.PINClient := TPINClient.Create('192.168.0.1',6969);
CCGlobal.ClientState := TCCClientState.create;
CCGlobal.ClientState.OutBoundRelay := CCGlobal.PINClient;
CCGlobal.PINClient.OutBoundRelay := CCGlobal.ClientState;
CCGlobal.PINClient.Connect;
end;
end;
end.
So yes, I shall be releasing this at some point but I'm looking for another developer to help me with the workload. There's still a number of widgets I need to re-code and I may need help on moving to a faster VBO rendering method (need new font units, is GLViewPort depreciated? EDIT : GLViewPort is *not* depreciated :) )
The old VFA is usable in much the same manner, but the design stinks. if you really want it, let me know.
and on a side note I've nearly finished PIN and I'm going to wrap up my hardware skinning lib from P3D, in my opinion the most modern skinning implementation in delphi (EDIT:FreePascal/Lazarus for me personally, all the way :) ) that I've seen so far, hence why I want to give it to the community.
Peace.