From 90db8b6652f73ddc335922d3a7c593878d83c45e Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sat, 4 Jan 2025 20:41:26 +0100 Subject: Basic ListView CSS styling --- UMain.pas | 209 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 103 insertions(+), 106 deletions(-) (limited to 'UMain.pas') diff --git a/UMain.pas b/UMain.pas index 0c17c7f..87df6c0 100644 --- a/UMain.pas +++ b/UMain.pas @@ -23,7 +23,7 @@ interface uses StrUtils, SysUtils, Types, Classes, DateUtils, - lazglib2, lazgobject2, lazpango1, lazgdkpixbuf2, lazgdk3, lazgtk3, + lazglib2, lazgobject2, lazgdk3, lazgtk3, GTKForms, GTKControls, GTKMenus, GTKStdCtrls, GTKExtCtrls, GTKView, GTKConsts, GTKUtils, GTKClasses, GTKPixbuf, UEngines, UConfig, UGnome, UVFSCore, UCoreClasses; @@ -1055,13 +1055,12 @@ procedure TFMain.ConstructColumns(ListView: TGTKListView); var i, FirstColumn, LastColumn: integer; HandlerID: gulong; Column: TGTKTreeViewColumn; - FontDesc: PPangoFontDescription; begin ListView.SelectionMode := smBrowse; GetFirstLastPanelColumn(FirstColumn, LastColumn); // Temporarily disable the fixed height mode to be able to add columns the Pascal way - g_object_set(PGObject(ListView.FWidget), 'fixed_height_mode', [0, nil]); + ListView.FixedHeightMode := False; for i := 1 to ConstNumPanelColumns do if ConfColumnVisible[i] then begin @@ -1088,7 +1087,6 @@ begin Column.Resizable := True; Column.Reorderable := True; -// if not ConfUseSystemFont then ListView.Columns[i - 1].SetProperty('font', ConfPanelFont); Column.SetProperty('ypad', 0); Column.SetProperty('yalign', 0.5); Column.Tag := i; @@ -1112,16 +1110,7 @@ begin HandlerID := g_signal_connect_data(PGObject(Column.FColumn), 'notify::width', TGCallback(@ListViewColumnResized), ListView, nil, G_CONNECT_DEFAULT); g_object_set_data(PGObject(Column.FColumn), 'Width_Notify_Handler', Pointer(HandlerID)); end; - - // Set the list font - // TODO -{ - if not ConfUseSystemFont then begin - FontDesc := pango_font_description_from_string(PChar(ConfPanelFont)); - gtk_widget_modify_font(ListView.FWidget, FontDesc); - end else gtk_widget_modify_font(ListView.FWidget, nil); -} - g_object_set(PGObject(ListView.FWidget), 'fixed_height_mode', [1, nil]); + ListView.FixedHeightMode := True; end; procedure TFMain.FormDestroy(Sender: TObject); @@ -1179,7 +1168,7 @@ begin end; *) ApplicationShuttingDown := True; // Avoid emitting config files refresh event - + // Close all active connections if b then begin if (not LeftPanelNotebook.Visible) and (LeftPanelEngine is TVFSEngine) then begin @@ -1224,19 +1213,12 @@ begin // Unset the columns changed signal because it's called on window close LeftListView.OnColumnsChanged := nil; RightListView.OnColumnsChanged := nil; - + ConfMainWindowState := Integer(WindowState); - if ConfMainWindowState <> 0 then begin - ConfMainWindowPosLeft := TGTKControl(Self).Left; - ConfMainWindowPosTop := TGTKControl(Self).Top; - ConfMainWindowWidth := TGTKControl(Self).Width; - ConfMainWindowHeight := TGTKControl(Self).Height; - end else begin - ConfMainWindowPosLeft := Left; - ConfMainWindowPosTop := Top; - ConfMainWindowWidth := Width; - ConfMainWindowHeight := Height; - end; + ConfMainWindowPosLeft := Left; + ConfMainWindowPosTop := Top; + ConfMainWindowWidth := Width; + ConfMainWindowHeight := Height; for i := 0 to LeftListView.Columns.Count - 1 do ConfColumnSizes[LeftListView.Columns[i].Tag] := LeftListView.Columns[i].Width; ConfMainWindowLeftSortColumn := LeftListView.SortColumnID; @@ -1285,10 +1267,10 @@ begin FillPluginMenu; - FileListTipsInstall(PGtkTreeView(LeftListView.FWidget)); +{ FileListTipsInstall(PGtkTreeView(LeftListView.FWidget)); FileListTipsInstall(PGtkTreeView(RightListView.FWidget)); FileListTipsEnable; - +} // Load and restore panel tabs if ConfSavePanelTabs then try TmpList := TStringList.Create; @@ -1810,7 +1792,7 @@ begin ATabList := RightPanelTabs; TabEngines := RightTabEngines; end; - try +// try if (NewPath = '..') and (Engine.ParentEngine <> nil) and (Engine.Path = '/') then begin CloseVFS(LeftPanel, False); Exit; @@ -1833,7 +1815,7 @@ begin // Threading... OpenDirThread := TOpenDirThread.Create; - DebugMsg(['TFMain.ChangingDir: Creating thread...']); +// DebugMsg(['TFMain.ChangingDir: Creating thread...']); DoThread; if Plugin <> nil then begin @@ -1844,29 +1826,32 @@ begin // Silence the error if password dialog has been cancelled if not OpenDirThread.VFSCallbackCancelled then ShowError(Self, LANGCouldntOpenURIArchive, OpenDirThread.VFSOpenError); - DebugMsg(['TFMain.ChangingDir: Freeing thread...']); +// DebugMsg(['TFMain.ChangingDir: Freeing thread...']); OpenDirThread.Free; end else if not OpenDirThread.ChDirResult then begin // Drop the error message if one of the callback dialogs were cancelled if not OpenDirThread.VFSCallbackCancelled then ShowError(Self, 'Error changing directory', OpenDirThread.ChDirError); - DebugMsg(['TFMain.ChangingDir: Freeing thread...']); +// DebugMsg(['TFMain.ChangingDir: Freeing thread...']); OpenDirThread.Free; end else if not OpenDirThread.ListingResult then begin ShowError(Self, Format('Error getting listing for %s panel', [LANGPanelStrings[LeftPanel]]), OpenDirThread.ListingError); - DebugMsg(['TFMain.ChangingDir: Freeing thread...']); +// DebugMsg(['TFMain.ChangingDir: Freeing thread...']); OpenDirThread.Free; end else begin s := OpenDirThread.ASelItem; Engine := OpenDirThread.AEngine; // set current Engine from the thread (might have been modified due to VFS) if LeftPanel then LeftPanelEngine := Engine else RightPanelEngine := Engine; - DebugMsg(['TFMain.ChangingDir: Freeing thread...']); +// DebugMsg(['TFMain.ChangingDir: Freeing thread...']); OpenDirThread.Free; - FillPanel(DirList, ListView, Engine, LeftPanel); // This is time consuming + // Prevent GtkTreeView accessing invalid item memory + ListView.CellDataFunc := nil; + + FillPanel(DirList, ListView, Engine, LeftPanel); DirList.Free; if DataList.Count > 0 then begin if PreserveSelection and (SelectedFiles.Count > 0) and (DataList.Count > 0) then @@ -1882,10 +1867,9 @@ begin // DebugMsg(['TFMain.ChangingDir: Engine.Path = "', Engine.Path, '", NewPath = "', NewPath, '", HiliString1 = "', HiliString1, '", HiliString2 = "', HiliString2, '"']); if (not b) and ((Engine.Path = '/') or (NewPath = '/')) and (HiliString1 = '') and (HiliString2 = '') then Sel := ListView.ConvertFromSorted(0); ListView.Items[Sel].Selected := True; -// Application.ProcessMessages; ListView.Items[Sel].SetCursor(0, False, False, 0.5, 0); -// Application.ProcessMessages; end; + ListView.CellDataFunc := @ListViewCellDataFunc; UpdatePanelInfo; UpdatePanelInfoDown(LeftPanel); UpdatePanelInfoDown(not LeftPanel); @@ -1901,9 +1885,9 @@ begin Application.ProcessMessages; InternalUnLock; FileListTipsEnable; - except +{ except on E: Exception do DebugMsg(['*** Exception raised in TFMain.ChangingDir (', E.ClassName, '): ', E.Message]); - end; + end; } end; procedure TFMain.DoRefresh(LeftPanel, StaySame, AutoFallback: boolean); @@ -2199,8 +2183,9 @@ var i: integer; begin Result := False; // TODO -{ for i := 0 to AListView.Columns.Count - 1 do - if Assigned(AListView.Columns[i].FColumn^.editable_widget) then Result := True; } +{ for i := 0 to AListView.Columns.Count - 1 do begin + if Assigned(AListView.Columns[i].FColumn^.editable_widget) then Result := True; + end; } end; function TFMain.PanelFindEditableWidget(AListView: TGTKListView): PGtkEditable; @@ -2249,23 +2234,27 @@ begin end; (********************************************************************************************************************************) -procedure TFMain.ListViewCellDataFunc(Sender: TObject; tree_view: PGtkTreeView; tree_column : PGtkTreeViewColumn; cell : PGtkCellRenderer; tree_model : PGtkTreeModel; iter : PGtkTreeIter); + +function GTK_IS_CELL_RENDERER_PIXBUF(obj: pointer) : boolean; +begin + Result := g_type_check_instance_is_a(obj, gtk_cell_renderer_pixbuf_get_type()); +end; + + +procedure TFMain.ListViewCellDataFunc(Sender: TObject; tree_view: PGtkTreeView; tree_column: PGtkTreeViewColumn; cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter); var s: PChar; Sel, ImageCol: boolean; Data: PDataItem; i, ColumnID, ColumnIdx: integer; DataList: TList; TreePath: PGtkTreePath; - AFGColor, ABGColor: string; - ABGColorRGBA: TGdkRGBA; -{ Rect, VisibleRect: TGdkRectangle; } + AFGColor: PGdkRGBA; begin + Data := nil; + ImageCol := False; ColumnIdx := gtk_tree_view_column_get_sort_column_id(tree_column); ColumnID := ColumnSortIDs[ColumnIdx + 1] - 1; - ImageCol := False; - // TODO - if ColumnIdx = 0 then ImageCol := Assigned(cell); - Data := nil; + if ColumnIdx = 0 then ImageCol := Assigned(cell) and GTK_IS_CELL_RENDERER_PIXBUF(cell); if Sender = LeftListView then DataList := LeftPanelData else DataList := RightPanelData; TreePath := gtk_tree_model_get_path(tree_model, iter); @@ -2273,18 +2262,12 @@ begin (Sender as TGTKListView).ConvertPathToChild(TreePath); Data := DataList[gtk_tree_path_get_indices(TreePath)^]; gtk_tree_path_free(TreePath); -(* gtk_tree_view_get_cell_area(tree_view, TreePath, nil, @Rect); - gtk_tree_view_get_visible_rect(tree_view, @VisibleRect); - if (Rect.height = 0) or (Rect.height <> ConfRowHeight) or (Rect.y = 0) or (Rect.y > VisibleRect.y + VisibleRect.height) then Exit; *) - -// DebugMsg(['Rendering text ', Data^.ColumnData[ColumnID]]); - if not Assigned(Data) then Exit; + Sel := gtk_tree_selection_iter_is_selected((Sender as TGTKView).FSelection, iter); with Data^ do begin // ################ Prepare colors - // TODO -{ + AFGColor := nil; if Selected then AFGColor := SelectedItemGDKColor else begin if Sel then begin if (Sender as TGTKView).Focused @@ -2292,31 +2275,22 @@ begin else AFGColor := InactiveItemGDKColor; end else AFGColor := ItemColor; end; - if not Sel then ABGColor := NormalItemGDKBackground else - if (Sender as TGTKView).Focused then ABGColor := ActiveItemGDKBackground - else ABGColor := InactiveItemGDKBackground; - // TODO - FG - gdk_rgba_parse(@ABGColorRGBA, PChar(ABGColor)); -} // ################ Setting the properties if not ImageCol then begin if Editing and (InplaceEditItem.Data = Data) and (ColumnID < 3) and ((ColumnID = 0) or (ColumnID = 1) { TODO or Assigned(tree_column^.editable_widget)}) then begin if (ColumnID = 0) or (ColumnID = 1) then s := FDisplayName else s := nil; - // TODO - g_object_set(PGObject(cell), 'text', [s, 'foreground-gdk', PChar(AFGColor), nil]); - g_object_set(PGObject(cell), 'cell-background-rgba', [@ABGColorRGBA, nil]); + g_object_set(PGObject(cell), 'text', ['foreground-rgba', AFGColor, nil]); end else begin // not editing if ConfDirsInBold then begin - if IsDir or UpDir then g_object_set(PGObject(cell), 'markup', [PChar(Format('%s', [QuoteMarkupStr(ColumnData[ColumnID])])), 'foreground-gdk', PChar(AFGColor), nil]) - else g_object_set(PGObject(cell), 'markup', [PChar(QuoteMarkupStr(ColumnData[ColumnID])), 'foreground-gdk', PChar(AFGColor), nil]); - end else g_object_set(PGObject(cell), 'text', [ColumnData[ColumnID], 'foreground-gdk', PChar(AFGColor), nil]); - g_object_set(PGObject(cell), 'cell-background-rgba', [@ABGColorRGBA, nil]); + if IsDir or UpDir then g_object_set(PGObject(cell), 'markup', [PChar(Format('%s', [QuoteMarkupStr(ColumnData[ColumnID])])), nil]) + else g_object_set(PGObject(cell), 'markup', [PChar(QuoteMarkupStr(ColumnData[ColumnID])), nil]); + end else g_object_set(PGObject(cell), 'text', [ColumnData[ColumnID], nil]); + g_object_set(PGObject(cell), 'foreground-rgba', [AFGColor, nil]); end; - end else // this is the image column + end else // this is an image column if ConfUseFileTypeIcons then begin // Assign icons - g_object_set(PGObject(cell), 'cell-background-rgba', [@ABGColorRGBA, nil]); if Sel and (not (Sender as TGTKView).Focused) then begin if Sender = LeftListView then RedrawLeftInactive := True else RedrawRightInactive := True; @@ -2855,6 +2829,7 @@ var AListView: TGTKListView; i: integer; s1, s2: string; begin + Exit; try InternalLock; AListView := (((Sender as TGTKTreeViewColumn).Parent as TGTKTreeViewColumns).Parent as TGTKListView); @@ -3107,9 +3082,8 @@ begin b := False; for i := 0 to DataList.Count - 1 do with PDataItem(DataList[i])^ do - if (not UpDir) and (not IsDir) and Selected then {$B+} + if (not UpDir) and (not IsDir) and Selected then b := b or FChecksum.ProcessFile(IncludeTrailingPathDelimiter(Engine.Path) + string(FName)); - {$B-} end; if b { and (FChecksum.List.Count > 0) } then FChecksum.Run; finally @@ -4354,6 +4328,7 @@ end; procedure TFMain.ApplySettings(RebuildListViews, RebuildIcons, AStartup: boolean); var i: integer; + CSS: string; begin ButtonsBox.Visible := ConfShowFuncButtons; ButtonBoxSeparator.Visible := ConfShowFuncButtons; @@ -4378,22 +4353,46 @@ begin // Colors Section SetupColors; - // TODO -{ - gtk_widget_modify_base(LeftListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKBackground); - gtk_widget_modify_base(RightListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKBackground); - gtk_widget_modify_base(LeftListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKBackground); - gtk_widget_modify_base(RightListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKBackground); - gtk_widget_modify_base(LeftListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKBackground); - gtk_widget_modify_base(RightListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKBackground); - - gtk_widget_modify_text(LeftListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKColor); - gtk_widget_modify_text(RightListView.FWidget, GTK_STATE_NORMAL, NormalItemGDKColor); - gtk_widget_modify_text(LeftListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKColor); - gtk_widget_modify_text(RightListView.FWidget, GTK_STATE_SELECTED, ActiveItemGDKColor); - gtk_widget_modify_text(LeftListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKColor); - gtk_widget_modify_text(RightListView.FWidget, GTK_STATE_ACTIVE, InactiveItemGDKColor); -} + + CSS := ''; +// CSS := CSS + '* { all: unset; -gtk-outline-radius: 0px; outline-color: transparent; outline-style: none; outline-offset: 0px; outline-width: 0px; }'#10; + CSS := CSS + 'treeview.view:nth-child(2) {'#10; + CSS := CSS + ' -gtk-outline-radius: 0px;'#10' outline-color: transparent;'#10' outline-style: none;'#10' outline-offset: 0px;'#10' outline-width: 0px;'#10; + if not ConfUseSystemFont then CSS := CSS + ' ' + PangoFontDescToCSS(ConfPanelFont) + #10; + if Assigned(NormalItemGDKBackground) then CSS := CSS + ' background-color: ' + GDKRGBAToString(NormalItemGDKBackground) + ';'#10; + if Assigned(NormalItemGDKColor) then CSS := CSS + ' color: ' + GDKRGBAToString(NormalItemGDKColor) + ';'#10; +// CSS := CSS + ' -GtkTreeView-vertical-separator: 10px;'#10' -GtkTreeView-horizontal-separator: 10px;'#10; + + CSS := CSS + '}'#10; + +(* CSS := CSS + 'row, .row, .cell, treeview.cell, treeview.row, treeview cell, treeview row {'#10 + + ' border-width: 0px; border-radius: 0px; border-image: none; border: none;'#10 + + ' background-color:yellow; background-image: none;'#10 + + ' padding: 0px; margin: 0px; box-shadow: none; '#10 + + ' outline-style: none; outline-offset: 0px; outline-width: 0px; outline-color: yellow;'#10 + + '}'#10; +*) + + if Assigned(ActiveItemGDKBackground) or Assigned(ActiveItemGDKColor) then begin + CSS := CSS + 'treeview.cell:selected:focus {'#10; + if Assigned(ActiveItemGDKColor) then CSS := CSS + ' color: ' + GDKRGBAToString(ActiveItemGDKColor) + ';'#10; + if Assigned(ActiveItemGDKBackground) then CSS := CSS + ' background-color: ' + GDKRGBAToString(ActiveItemGDKBackground) + ';'#10 + + ' background-image: image(' + GDKRGBAToString(ActiveItemGDKBackground) + ');'#10 + + ' border-style: none; border-width: 0;'#10; + CSS := CSS + '}'#10; + end; + if Assigned(InactiveItemGDKBackground) or Assigned(InactiveItemGDKColor) then begin + CSS := CSS + 'treeview.cell:selected {'#10; + if Assigned(InactiveItemGDKColor) then CSS := CSS + ' color: ' + GDKRGBAToString(InactiveItemGDKColor) + ';'#10; + if Assigned(InactiveItemGDKBackground) then CSS := CSS + ' background-color: ' + GDKRGBAToString(InactiveItemGDKBackground) + ';'#10 + + ' background-image: image(' + GDKRGBAToString(InactiveItemGDKBackground) + ');'#10 + + ' border-style: none; border-width: 0;'#10; + CSS := CSS + '}'#10; + end; + writeln(css); + LeftListView.ApplyCustomCSS(CSS); + RightListView.ApplyCustomCSS(CSS); + // Resize commandline history if ConfNumHistoryItems < CommandLineHistory.Count then begin try @@ -4798,11 +4797,10 @@ procedure TFMain.FillMounterBar; 3 : Pixmap := MounterFloppy; 4 : Pixmap := MounterNetwork; end; - // TODO if ConfMounterPushDown then begin -// (Button as TGTKToggleButton).Icon := Pixmap; + (Button as TGTKToggleButton).Icon := Pixmap; (Button as TGTKToggleButton).Checked := Mounted; - end; // TODO else Button.Icon := Pixmap; + end else Button.Icon := Pixmap; Button.OnClick := @MounterButtonClick; // It has to be here because setting the Checked property causes the signal emitting Button.MarginTop := 1; @@ -5004,7 +5002,6 @@ begin try InternalLock; FColumns := TFColumns.Create(Self); -// FColumns.Show; if FColumns.Run = mbOK then begin FColumns.ApplyColumnList; RebuildListViews(True); @@ -5151,19 +5148,19 @@ begin end; procedure TFMain.miPluginAboutClick(Sender: TObject); -const Authors : array[0..1] of PChar = ('', nil); -var AboutBox: PGtkWidget; - VFSItem: TVFSPlugin; +var VFSItem: TVFSPlugin; + about_dialog: PGtkWidget; begin + InternalLock; VFSItem := TVFSPlugin(PluginList[(Sender as TGTKMenuItem).Tag]); - InternalLock; - // TODO - Application.MessageBox(Format(LANGPluginAboutInside, [VFSItem.ModuleName, VFSItem.ModuleAbout, VFSItem.ModuleCopyright])); -{ else begin - AboutBox := gnome_about_new(PChar(VFSItem.ModuleName), nil, PChar(VFSItem.ModuleCopyright), PChar(VFSItem.ModuleAbout), @Authors, nil, nil, AppIcon64.FPixbuf); - gtk_window_set_transient_for(PGtkWindow(AboutBox), PGtkWindow(FMain.FWidget)); - gtk_dialog_run(PGtkDialog(AboutBox)); - end; } + about_dialog := gtk_about_dialog_new(); + gtk_about_dialog_set_program_name(PGtkAboutDialog(about_dialog), PChar(VFSItem.ModuleName)); + gtk_about_dialog_set_version(PGtkAboutDialog(about_dialog), PChar(VFSItem.ModuleAbout)); + gtk_about_dialog_set_copyright(PGtkAboutDialog(about_dialog), PChar(VFSItem.ModuleCopyright)); + gtk_about_dialog_set_logo(PGtkAboutDialog(about_dialog), AppIcon64.FPixbuf); + gtk_window_set_transient_for(PGtkWindow(about_dialog), PGtkWindow(FMain.FWidget)); + gtk_dialog_run(PGtkDialog(about_dialog)); + gtk_widget_destroy(about_dialog); InternalLockInit(False); end; -- cgit v1.2.3