feat: update

This commit is contained in:
anjingyu 2025-07-11 20:10:03 +08:00
parent 4b39cc6094
commit ec4b4f5e41
3 changed files with 373 additions and 2 deletions

View File

@ -0,0 +1,16 @@
cmake_minimum_required (VERSION 3.15)
project (dbcc_gui)
include (CMakeListsPub)
set (TARGET_NAME ${CMAKE_PROJECT_NAME})
append_modules (dbcc)
append_3rd_modules (fltk)
file (GLOB_RECURSE SRC
"${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
add_executable (${TARGET_NAME} ${SRC})
add_dependencies (${TARGET_NAME} ${DBCC_DEPS} ${FLTK_DPES})
target_link_libraries (${TARGET_NAME} ${DBCC_LIB} ${FLTK_LIB})

View File

@ -0,0 +1,355 @@
#include <cstdint>
#include <iostream>
#include "FL/Fl.H"
#include "FL/Fl_Double_Window.H"
#include "FL/Fl_Tree.H"
constexpr const int32_t kLeftMargin = 5;
const char * const kTreeOpenXpm[] = {
"11 11 3 1",
". c #fefefe",
"# c #444444",
"@ c #000000",
"###########",
"#.........#",
"#.........#",
"#....@....#",
"#....@....#",
"#..@@@@@..#",
"#....@....#",
"#....@....#",
"#.........#",
"#.........#",
"###########"
};
const char * const kTreeCloseXpm[] = {
"11 11 3 1",
". c #fefefe",
"# c #444444",
"@ c #000000",
"###########",
"#.........#",
"#.........#",
"#.........#",
"#.........#",
"#..@@@@@..#",
"#.........#",
"#.........#",
"#.........#",
"#.........#",
"###########"
};
// DERIVE CUSTOM CLASS FROM Fl_Tree_Item TO SHOW DATA IN COLUMNS
class TreeRowItem : public Fl_Tree_Item {
public:
TreeRowItem(Fl_Tree *tree, const char *text) : Fl_Tree_Item(tree) {
this->label(text);
}
int draw_item_content(int render);
};
// Small convenience class to handle adding columns.
// TreeRowItem does most of the work.
//
class TreeWithColumns : public Fl_Tree {
bool colseps_flag; // enable/disable column separator lines
bool resizing_flag; // enable/disable interactive resizing
char col_char; // column delimiter character
int *col_widths; // array of column widths (supplied by application)
int first_col_minw; // minimum width of first column
int drag_col; // internal: column being FL_DRAG'ed
Fl_Cursor last_cursor; // internal: last mouse cursor value
protected:
int column_near_mouse() {
// Event not inside browser area? (eg. scrollbar) Early exit
if ( !Fl::event_inside(_tix,_tiy,_tiw,_tih) ) return(-1);
int mousex = Fl::event_x() + hposition();
int colx = x() + first_col_minw;
for ( int t=0; col_widths[t]; t++ ) {
colx += col_widths[t];
int diff = mousex - colx;
// Mouse near column? Return column #
if ( diff >= -4 && diff <= 4 ) return(t);
}
return(-1);
}
// Change the mouse cursor
// Does nothing if cursor already set to same value.
//
void change_cursor(Fl_Cursor newcursor) {
if ( newcursor == last_cursor ) return;
window()->cursor(newcursor);
last_cursor = newcursor;
}
public:
TreeWithColumns(int X,int Y,int W,int H,const char *L=0) : Fl_Tree(X,Y,W,H,L) {
colseps_flag = true;
resizing_flag = true;
col_char = '\t';
col_widths = 0;
first_col_minw = 80;
drag_col = -1;
last_cursor = FL_CURSOR_DEFAULT;
// We need the default tree icons on all platforms.
// For some reason someone made Fl_Tree have different icons on the Mac,
// which doesn't look good for this application, so we force the icons
// to be consistent with the '+' and '-' icons and dotted connection lines.
//
connectorstyle(FL_TREE_CONNECTOR_DOTTED);
openicon(new Fl_Pixmap(tree_open_xpm));
closeicon(new Fl_Pixmap(tree_close_xpm));
}
// The minimum width of column #1 in pixels.
// During interactive resizing, don't allow first column to be smaller than this.
//
int first_column_minw() { return first_col_minw; }
void first_column_minw(int val) { first_col_minw = val; }
// Enable/disable the vertical column lines
void column_separators(bool val) { colseps_flag = val; }
bool column_separators() const { return colseps_flag; }
// Enable/disable the vertical column lines
void resizing(bool val) { resizing_flag = val; }
bool resizing() const { return resizing_flag; }
// Change the column delimiter character
void column_char(char val) { this->col_char = val; }
char column_char() const { return col_char; }
// Set the column array.
// Make sure the last entry is zero.
// User allocated array must remain allocated for lifetime of class instance.
// Must be large enough for all columns in data!
//
void column_widths(int *val) { this->col_widths = val; }
int *column_widths() const { return col_widths; }
TreeRowItem *AddRow(const char *s, TreeRowItem *parent_item=0) {
TreeRowItem *item = new TreeRowItem(this, s); // create new item
if ( parent_item == 0 ) { // wants root item as parent?
if ( strcmp(root()->label(), "ROOT")==0 ) { // default root item?
this->root(item); // make this item the new root
// Special colors for root item -- this is the "header"
item->labelfgcolor(0xffffff00);
item->labelbgcolor(0x8888ff00);
return item;
} else {
parent_item = (TreeRowItem*)root(); // use root as parent
}
}
parent_item->add(prefs(), "", item); // add item to hierarchy
return item; // return the new item
}
// Manage column resizing
int handle(int e) {
if ( !resizing_flag ) return Fl_Tree::handle(e); // resizing off? early exit
// Handle column resizing
int ret = 0;
switch ( e ) {
case FL_ENTER:
ret = 1;
break;
case FL_MOVE:
change_cursor( (column_near_mouse() >= 0) ? FL_CURSOR_WE : FL_CURSOR_DEFAULT);
ret = 1;
break;
case FL_PUSH: {
int whichcol = column_near_mouse();
if ( whichcol >= 0 ) {
// Clicked on resizer? Start dragging that column
drag_col = whichcol;
change_cursor(FL_CURSOR_DEFAULT);
return 1; // eclipse event from Fl_Tree's handle()
}
break;
}
case FL_DRAG:
if ( drag_col != -1 ) {
// Sum up column widths to determine position
int mousex = Fl::event_x() + hposition();
int newwidth = mousex - (x() + first_column_minw());
for ( int t=0; col_widths[t] && t<drag_col; t++ )
{ newwidth -= col_widths[t]; }
// Apply new width, redraw interface
col_widths[drag_col] = newwidth;
if ( col_widths[drag_col] < 2 ) col_widths[drag_col] = 2; // XXX: 2 should be a class member
recalc_tree();
redraw();
return 1; // eclipse event from Fl_Tree's handle()
}
break;
case FL_LEAVE:
case FL_RELEASE:
change_cursor(FL_CURSOR_DEFAULT); // ensure normal cursor
if ( drag_col != -1 && e == FL_RELEASE ) { // release during drag mode?
drag_col = -1; // disable drag mode
return 1; // eclipse event from base class; we handled it
}
drag_col = -1;
ret = 1;
break;
}
return(Fl_Tree::handle(e) ? 1 : ret);
}
// Hide these base class methods from the API; we don't want app using them,
// as we expect all items in the tree to be TreeRowItems, not Fl_Tree_Items.
private:
using Fl_Tree::add;
};
// Handle custom drawing of the item
//
// All we're responsible for is drawing the 'label' area of the item
// and it's background. Fl_Tree gives us a hint as to what the
// foreground and background colors should be via the fg/bg parameters,
// and whether we're supposed to render anything or not.
//
// The only other thing we must do is return the maximum X position
// of scrollable content, i.e. the right most X position of content
// that we want the user to be able to use the horizontal scrollbar
// to reach.
//
int TreeRowItem::draw_item_content(int render) {
TreeWithColumns *treewc = (TreeWithColumns*)tree();
Fl_Color fg = drawfgcolor();
Fl_Color bg = drawbgcolor();
const int *col_widths = treewc->column_widths();
// Show the date and time as two small strings
// one on top of the other in a single item.
//
// Our item's label dimensions
int X = label_x(), Y = label_y(),
W = label_w(), H = label_h(),
RX = treewc->x() - treewc->hposition() + treewc->first_column_minw(), // start first column at a fixed position
RY = Y+H-fl_descent(); // text draws here
// Render background
if ( render ) {
if ( is_selected() ) { fl_draw_box(prefs().selectbox(),X,Y,W,H,bg); }
else { fl_color(bg); fl_rectf(X,Y,W,H); }
fl_font(labelfont(), labelsize());
}
if ( render ) fl_push_clip(X,Y,W,H);
// Render columns
// ⚠️ Be sure to conditionally call fl_pop_clip() before return() from this section
//
{
// Draw each column
// ..or if not rendering, at least calculate width of row so we can return it.
//
int t=0;
const char *s = label();
char delim_str[2] = { treewc->column_char(), 0 }; // strcspn() wants a char[]
while ( *s ) {
int n = strcspn(s, delim_str); // find index to next delimiter char in 's' (or eos if none)
if ( n>0 && render ) { // renderable string with at least 1 or more chars?
int XX = ( t==0 ) ? X : RX; // TBD: Rename XX to something more meaningful
// Don't clip last column.
// See if there's more columns after this one; if so, clip the column.
// If not, let column run to edge of widget
//
int CW = col_widths[t]; // clip width based on column width
// If first column, clip to 2nd column's left edge
if ( t==0 ) { CW = (RX+col_widths[0])-XX; }
// If last column, clip to right edge of widget
if ( *(s+n) == 0 ) { CW = (x()+w()-XX); }
// Draw the text
// We want first field (PID) indented, rest of fields fixed column.
//
fl_color(fg);
fl_push_clip(XX, Y, CW, H); // prevent text from running into next column
fl_draw(s, n, XX+LEFT_MARGIN, RY);
fl_pop_clip(); // clip off
// Draw vertical lines for all columns except first
if ( t>0 && treewc->column_separators() ) {
fl_color(FL_BLACK);
fl_line(RX,Y,RX,Y+H);
}
}
if ( *(s+n) == treewc->column_char() ) {
s += n+1; // skip field + delim
RX += col_widths[t++]; // keep track of fixed column widths for all except right column
continue;
} else {
// Last field? Return entire length of unclipped field
RX += fl_width(s) + LEFT_MARGIN;
s += n;
}
}
}
if ( render ) fl_pop_clip();
return RX; // return right most edge of what we've rendered
}
int main(int argc, char *argv[]) {
Fl::scheme("gtk+");
Fl_Double_Window *win = new Fl_Double_Window(550, 400, "Tree With Columns");
win->begin();
{
static int col_widths[] = { 80, 50, 50, 50, 0 };
// Create the tree
TreeWithColumns *tree = new TreeWithColumns(0, 0, win->w(), win->h());
tree->selectmode(FL_TREE_SELECT_MULTI); // multiselect
tree->column_widths(col_widths); // set column widths array
tree->resizing(true); // enable interactive resizing
tree->column_char('\t'); // use tab char as column delimiter
tree->first_column_minw(100); // minimum width of first column
// Add some items in a hierarchy:
//
// 5197 ? Ss 0:00 /usr/sbin/sshd -D
// 12807 ? Ss 0:00 \_ sshd: root@pts/6
// 12811 pts/6 Ss+ 0:00 | \_ -tcsh
// 3993 ? Ss 0:00 \_ sshd: erco [priv]
// 3997 ? S 0:00 \_ sshd: erco@pts/14
// 3998 pts/14 Ss+ 0:00 \_ -tcsh
// 5199 ? Ssl 8:02 /usr/sbin/rsyslogd -n
// 5375 ? Ss 0:00 /usr/sbin/atd -f
// 13778 ? Ss 0:00 \_ /usr/sbin/atd -f
// 13781 ? SN 0:00 | \_ sh
// 13785 ? SN 684:59 | \_ xterm -title Reminder: now -geometry 40x6-1+1 -fg white -bg #cc0000 -hold -font
//
TreeRowItem *top; // top of hierarchy
// First row is header
top = tree->AddRow("PID\tTTY\tSTAT\tTIME\tCOMMAND"); // first row is always the "header"
// Add the hierarchical rows of data..
top = tree->AddRow("5197\t?\tSs\t0:00\t/usr/sbin/sshd -D"); // top level
// Add 200 copies of data to tree to test performance
for ( int t=0; t<200; t++ ) {
{
TreeRowItem *child1 = tree->AddRow("12807\t?\tSs\t0:00\tsshd: root@pts/6", top);
{
tree->AddRow("12811\tpts/6\tSs+\t0:00\t-tcsh", child1);
}
child1 = tree->AddRow("3993\t?\tSs\t0:00\tsshd: erco [priv]", top);
{
TreeRowItem *child2 = tree->AddRow("3997\t?\tS\t0:00\tsshd: erco@pts/14", child1);
{
tree->AddRow("3998\tpts/14\tSs+\t0:00\t-tcsh", child2);
}
}
}
top = tree->AddRow("5199\t?\tSsl\t8:02\t/usr/sbin/rsyslogd -n");
top = tree->AddRow("5375\t?\tSs\t0:00\t/usr/sbin/atd -f");
{
TreeRowItem *child1 = tree->AddRow("13778\t?\tSs\t0:00\t/usr/sbin/atd -f", top);
{
TreeRowItem *child2 = tree->AddRow("13781\t?\tSN\t0:00\tsh", child1);
{
tree->AddRow("13785\t?\tSN\t684:59\txterm -title Reminder: now -geometry 40x6-1+1 -fg white -bg #cc0000 -hold -font", child2);
}
}
}
}
// tree->show_self();
}
win->end();
win->resizable(win);
win->show(argc, argv);
return(Fl::run());
}

View File

@ -2,7 +2,7 @@
name = "pyglcv"
version = "0.1.0"
description = ""
authors = ["anjingyu <anjingyu@navinfo.com>"]
authors = ["donkey <anjingyu_ws@foxmail.com>"]
readme = "README.md"
[tool.poetry.dependencies]
@ -19,5 +19,5 @@ build-backend = "poetry.core.masonry.api"
[[tool.poetry.source]]
name = "tsinghua"
url = "https://opentuna.cn/pypi/web/simple"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
priority = "default"