Gtk3: overrided GtkComboBox and GtkEntry, needed for proper sizing and autosizing of those controls.

This commit is contained in:
zeljan1 2025-01-17 18:25:00 +01:00
parent 62c808ee25
commit 0f12e6894a
2 changed files with 344 additions and 0 deletions

View File

@ -0,0 +1,186 @@
{%MainUnit gtk3widgets.pas}
const
GTK_COMBO_BOX_CLASS_SIZE = SizeOf(TGtkComboBoxClass); //1048
GTK_COMBO_BOX_INSTANCE_SIZE = SizeOf(TGtkComboBox); //56
procedure LCLGtkComboBoxGetPreferredWidth(widget: PGtkWidget; min_width, nat_width: Pgint); cdecl;
var
AControl:TGtk3Widget;
ParentClass:PGtkWidgetClass;
begin
if not Assigned(min_width) or not Assigned(nat_width) then
begin
DebugLn('Error: LCLGtkComboBoxGetPreferredWidth invalid params.');
Exit;
end;
if not Gtk3IsWidget(widget) then
begin
DebugLn('Error: LCLGtkComboBoxGetPreferredWidth widget param is not PGtkWidget.');
// WriteLn('Error: widget is not a valid GtkWidget');
Exit;
end;
ParentClass := PGtkWidgetClass(g_type_class_peek_parent(widget^.g_type_instance.g_class));
if not Assigned(ParentClass) then
begin
DebugLn('Error: cannot get ParentClass !');
exit;
end;
//check what parent class says about minimum and natural width.
ParentClass^.get_preferred_width(widget, min_width, nat_width);
AControl := TGtk3Widget(HwndFromGtkWidget(widget));
if not Assigned(AControl) then
begin
DebugLn('Error: cannot get TGtk3Widget for widget parameter.');
exit;
end;
// we don't check autosize since combo width is free size
if AControl.LCLWidth = 0 then
begin
min_width^ := Max(50, AControl.LCLObject.Width);
nat_width^ := Max(50, AControl.LCLObject.Width);
end else
begin
min_width^ := Max(50, AControl.LCLWidth);
nat_width^ := Max(50, AControl.LCLWidth);
end;
end;
procedure LCLGtkComboBoxGetPreferredHeight(widget: PGtkWidget; min_height, nat_height: Pgint); cdecl;
var
AControl:TGtk3Widget;
ParentClass:PGtkWidgetClass;
begin
if not Assigned(min_height) or not Assigned(nat_height) then
begin
DebugLn('Error: LCLGtkComboBoxGetPreferredWidth invalid params.');
Exit;
end;
if not Gtk3IsWidget(widget) then
begin
DebugLn('Error: LCLGtkComboBoxGetPreferredWidth widget param is not PGtkWidget.');
// WriteLn('Error: widget is not a valid GtkWidget');
Exit;
end;
ParentClass := PGtkWidgetClass(g_type_class_peek_parent(widget^.g_type_instance.g_class));
if not Assigned(ParentClass) then
begin
DebugLn('Error: cannot get ParentClass !');
exit;
end;
ParentClass^.get_preferred_height(widget, min_height, nat_height);
AControl := TGtk3Widget(HwndFromGtkWidget(widget));
if not Assigned(AControl) then
begin
DebugLn('Error: cannot get TGtk3Widget for widget parameter.');
exit;
end;
if AControl.LCLObject.AutoSize then
exit; // keep gtk calculated height.
if AControl.LCLHeight = 0 then
begin
min_height^ := Max(25, AControl.LCLObject.Height);
nat_height^ := Max(25, AControl.LCLObject.Height);
end else
begin
min_height^ := Max(25, AControl.LCLHeight);
nat_height^ := Max(25, AControl.LCLHeight);
end;
end;
procedure LCLGtkComboBoxClassInit(klass: PGTypeClass; data: Pointer); cdecl;
{$IFDEF GTK3DEBUGCOMBOBOX}
procedure WalkTypeHierarchy(klass: PGTypeClass);
begin
while Assigned(klass) do
begin
WriteLn('Class type: ', g_type_name(klass^.g_type));
klass := g_type_class_peek_parent(klass);
end;
end;
{$ENDIF}
var
AWidgetClass: PGtkWidgetClass;
begin
AWidgetClass := PGtkWidgetClass(klass);
AWidgetClass^.get_preferred_width := @LCLGtkComboBoxGetPreferredWidth;
AWidgetClass^.get_preferred_height := @LCLGtkComboBoxGetPreferredHeight;
{$IFDEF GTK3DEBUGCOMBOBOX}
//debug - looks ok.
//WalkTypeHierarchy(klass);
WalkParentClassHierarchy(klass);
{$ENDIF}
end;
procedure LCLGtkComboBoxInit(instance: PGTypeInstance; klass: PGTypeClass); cdecl;
var
combowidget:PGtkComboBox;
{%H-}AStyle:PGtkStyleContext;
//Alloc:TGtkAllocation;
begin
combowidget := PGtkComboBox(instance);
{we can initialize here any default values
Alloc.x := 0;
Alloc.Y := 0;
Alloc.Width := 75; // default
Alloc.Height := 25; // default
comboWidget^.set_allocation(@Alloc);
}
AStyle := comboWidget^.get_style_context;
end;
var
lclCombotype: TGType = 0;
function LCLGtkComboBoxGetType: TGType; cdecl;
const
lcl_combo_box_type_info: TGTypeInfo = (
class_size: GTK_COMBO_BOX_CLASS_SIZE;
base_init: nil;
base_finalize: nil;
class_init: @LCLGtkComboBoxClassInit;
class_finalize: nil;
class_data: nil;
instance_size: GTK_COMBO_BOX_INSTANCE_SIZE;
n_preallocs: 0;
instance_init: @LCLGtkComboBoxInit;
value_table: nil;
);
begin
if lclCombotype = 0 then
lclCombotype := g_type_register_static(gtk_combo_box_get_type, 'LCLGtkComboBox', PGTypeInfo(@lcl_combo_box_type_info), G_TYPE_FLAG_NONE);
Result := lclCombotype;
end;
function LCLGtkComboBoxNewWithModelAndEntry(model: PGtkTreeModel): PGtkComboBox;
begin
Result := PGtkComboBox(g_object_new(LCLGtkComboBoxGetType,
'model', [model,
'has-entry', gboolean(true),
nil]));
end;
function LCLGtkComboBoxNewWithModel(model: PGtkTreeModel): PGtkWidget;
begin
Result := PGtkComboBox(g_object_new(LCLGtkComboBoxGetType,
'model',[model,
'has-entry', gboolean(false),
nil]));
end;

View File

@ -0,0 +1,158 @@
{%MainUnit gtk3widgets.pas}
const
GTK_ENTRY_CLASS_SIZE = SizeOf(TGtkEntryClass);
GTK_ENTRY_INSTANCE_SIZE = SizeOf(TGtkEntry);
procedure LCLGtkEntryGetPreferredWidth(widget: PGtkWidget; min_width, nat_width: Pgint); cdecl;
var
AControl: TGtk3Widget;
ParentClass: PGtkWidgetClass;
begin
if not Assigned(min_width) or not Assigned(nat_width) then
begin
DebugLn('Error: LCLGtkEntryGetPreferredWidth invalid params.');
Exit;
end;
if not Gtk3IsWidget(widget) then
begin
DebugLn('Error: LCLGtkEntryGetPreferredWidth widget param is not PGtkWidget.');
Exit;
end;
ParentClass := PGtkWidgetClass(g_type_class_peek_parent(widget^.g_type_instance.g_class));
if not Assigned(ParentClass) then
begin
DebugLn('Error: cannot get ParentClass !');
Exit;
end;
// Call parent class implementation
ParentClass^.get_preferred_width(widget, min_width, nat_width);
AControl := TGtk3Widget(HwndFromGtkWidget(widget));
if not Assigned(AControl) then
begin
DebugLn('Error: cannot get TGtk3Widget for widget parameter.');
Exit;
end;
// we pass our width , no matter autosize is on or off.
if AControl.LCLWidth = 0 then
begin
min_width^ := Max(30, AControl.LCLObject.Width);
nat_width^ := Max(30, AControl.LCLObject.Width);
end else
begin
min_width^ := Max(30, AControl.LCLWidth);
nat_width^ := Max(30, AControl.LCLWidth);
end;
end;
procedure LCLGtkEntryGetPreferredHeight(widget: PGtkWidget; min_height, nat_height: Pgint); cdecl;
var
AControl: TGtk3Widget;
ParentClass: PGtkWidgetClass;
begin
if not Assigned(min_height) or not Assigned(nat_height) then
begin
DebugLn('Error: LCLGtkEntryGetPreferredHeight invalid params.');
Exit;
end;
if not Gtk3IsWidget(widget) then
begin
DebugLn('Error: LCLGtkEntryGetPreferredHeight widget param is not PGtkWidget.');
Exit;
end;
ParentClass := PGtkWidgetClass(g_type_class_peek_parent(widget^.g_type_instance.g_class));
if not Assigned(ParentClass) then
begin
DebugLn('Error: cannot get ParentClass !');
Exit;
end;
// Call parent class implementation
ParentClass^.get_preferred_height(widget, min_height, nat_height);
AControl := TGtk3Widget(HwndFromGtkWidget(widget));
if not Assigned(AControl) then
begin
DebugLn('Error: cannot get TGtk3Widget for widget parameter.');
Exit;
end;
// we respect ws height if autosize is true.
if AControl.LCLObject.AutoSize then
exit;
if AControl.LCLHeight = 0 then
begin
min_height^ := Max(20, AControl.LCLObject.Height);
nat_height^ := Max(20, AControl.LCLObject.Height);
end else
begin
min_height^ := Max(20, AControl.LCLHeight);
nat_height^ := Max(20, AControl.LCLHeight);
end;
end;
procedure LCLGtkEntryClassInit(klass: PGTypeClass; {%H-}data: Pointer); cdecl;
var
AWidgetClass: PGtkWidgetClass;
begin
AWidgetClass := PGtkWidgetClass(klass);
AWidgetClass^.get_preferred_width := @LCLGtkEntryGetPreferredWidth;
AWidgetClass^.get_preferred_height := @LCLGtkEntryGetPreferredHeight;
end;
procedure LCLGtkEntryInstanceInit(instance: PGTypeInstance; {%H-}klass: PGTypeClass); cdecl;
var
entryWidget: PGtkEntry;
//Alloc: TGtkAllocation;
{%H-}AStyle:PGtkStyleContext;
begin
entryWidget := PGtkEntry(instance);
{ Initialize default allocation
Alloc.x := 0;
Alloc.Y := 0;
Alloc.Width := 75; // Default width
Alloc.Height := 25; // Default height
entryWidget^.set_allocation(@Alloc);
}
AStyle := entryWidget^.get_style_context;
// writeln('StyleContext ? ',AStyle <> nil,' Scale=',AStyle^.get_scale);
end;
var
LCLGtkEntryType: TGType = 0;
function LCLGtkEntryGetType: TGType; cdecl;
const
lcl_entry_type_info: TGTypeInfo = (
class_size: GTK_ENTRY_CLASS_SIZE;
base_init: nil;
base_finalize: nil;
class_init: @LCLGtkEntryClassInit;
class_finalize: nil;
class_data: nil;
instance_size: GTK_ENTRY_INSTANCE_SIZE;
n_preallocs: 0;
instance_init: @LCLGtkEntryInstanceInit;
value_table: nil;
);
begin
if LCLGtkEntryType = 0 then
LCLGtkEntryType := g_type_register_static(gtk_entry_get_type, 'LCLGtkEntry', @lcl_entry_type_info, G_TYPE_FLAG_NONE);
Result := LCLGtkEntryType;
end;
function LCLGtkEntryNew: PGtkEntry;
begin
Result := PGtkEntry(g_object_new(LCLGtkEntryGetType(), 'editable', [gboolean(True), nil]));
end;