From ec05f78d98d8e38ea34eb1bd73647fa5b8b35f81 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Tue, 27 Aug 2024 15:13:32 +0200 Subject: [PATCH] Adding horiizonatl and vertical label margin - sizeof(Fl_Widget) not increased - label positions can be adjusted - try it out in test/label app - full support in FLUD --- FL/Fl_Widget.H | 24 +++++++++++++ fluid/Fl_Widget_Type.cxx | 76 ++++++++++++++++++++++++++++++++++++++-- fluid/README_fl.txt | 2 ++ fluid/widget_panel.cxx | 51 +++++++++++++++++++++------ fluid/widget_panel.fl | 31 ++++++++++++---- fluid/widget_panel.h | 2 ++ src/Fl_Choice.cxx | 2 +- src/Fl_Menu.cxx | 4 +-- src/Fl_Widget.cxx | 1 + src/Fl_Window.cxx | 2 +- src/fl_labeltype.cxx | 24 +++++++++++++ test/label.cxx | 48 +++++++++++++++++++------ 12 files changed, 235 insertions(+), 32 deletions(-) diff --git a/FL/Fl_Widget.H b/FL/Fl_Widget.H index 7dc90069c..c9fe89bba 100644 --- a/FL/Fl_Widget.H +++ b/FL/Fl_Widget.H @@ -63,6 +63,10 @@ struct FL_EXPORT Fl_Label { Fl_Align align_; /** type of label. \see Fl_Labeltype */ uchar type; + /** Spacing between label and the horizontally aligned side of the widget. */ + signed char h_margin_; + /** Spacing between label and the vertically aligned side of the widget. */ + signed char v_margin_; /** Spacing between an image and the label text */ uchar spacing; @@ -698,6 +702,26 @@ public: */ int label_image_spacing() { return label_.spacing; } + /** Set the spacing between the label and the horizontal edge of the widget. + \param[in] px gap in pixels + */ + void horizontal_label_margin(int px) { label_.h_margin_ = (signed char)px; } + + /** Get the spacing between the label and the horizontal edge of the widget. + \return px gap in pixels + */ + int horizontal_label_margin() { return label_.h_margin_; } + + /** Set the spacing between the label and the vertical edge of the widget. + \param[in] px gap in pixels + */ + void vertical_label_margin(int px) { label_.v_margin_ = (signed char)px; } + + /** Get the spacing between the label and the vertical edge of the widget. + \return px gap in pixels + */ + int vertical_label_margin() { return label_.v_margin_; } + /** Gets the current tooltip text. \return a pointer to the tooltip text or NULL \see tooltip(const char*), copy_tooltip(const char*) diff --git a/fluid/Fl_Widget_Type.cxx b/fluid/Fl_Widget_Type.cxx index 6b86e6ae0..2e1cee809 100644 --- a/fluid/Fl_Widget_Type.cxx +++ b/fluid/Fl_Widget_Type.cxx @@ -1985,8 +1985,66 @@ void image_spacing_cb(Fl_Value_Input* i, void* v) { Fl_Widget_Type* q = (Fl_Widget_Type*)o; if (q->o->label_image_spacing() != s) { q->o->label_image_spacing(s); - if (q->o->parent()) - q->o->parent()->damage(FL_DAMAGE_EXPOSE); // outside labels + if (!(q->o->align() & FL_ALIGN_INSIDE) && q->o->window()) + q->o->window()->damage(FL_DAMAGE_EXPOSE); // outside labels + q->o->redraw(); + mod = 1; + } + } + } + if (mod) set_modflag(1); + } +} + +void h_label_margin_cb(Fl_Value_Input* i, void* v) { + int s; + if (v == LOAD) { + if (!current_widget->is_true_widget()) { + i->deactivate(); + i->value(0); + } else { + i->activate(); + i->value(((Fl_Widget_Type*)current_widget)->o->horizontal_label_margin()); + } + } else { + int mod = 0; + s = int(i->value()); + for (Fl_Type *o = Fl_Type::first; o; o = o->next) { + if (o->selected && o->is_true_widget()) { + Fl_Widget_Type* q = (Fl_Widget_Type*)o; + if (q->o->horizontal_label_margin() != s) { + q->o->horizontal_label_margin(s); + if (!(q->o->align() & FL_ALIGN_INSIDE) && q->o->window()) + q->o->window()->damage(FL_DAMAGE_EXPOSE); // outside labels + q->o->redraw(); + mod = 1; + } + } + } + if (mod) set_modflag(1); + } +} + +void v_label_margin_cb(Fl_Value_Input* i, void* v) { + int s; + if (v == LOAD) { + if (!current_widget->is_true_widget()) { + i->deactivate(); + i->value(0); + } else { + i->activate(); + i->value(((Fl_Widget_Type*)current_widget)->o->vertical_label_margin()); + } + } else { + int mod = 0; + s = int(i->value()); + for (Fl_Type *o = Fl_Type::first; o; o = o->next) { + if (o->selected && o->is_true_widget()) { + Fl_Widget_Type* q = (Fl_Widget_Type*)o; + if (q->o->vertical_label_margin() != s) { + q->o->vertical_label_margin(s); + if (!(q->o->align() & FL_ALIGN_INSIDE) && q->o->window()) + q->o->window()->damage(FL_DAMAGE_EXPOSE); // outside labels q->o->redraw(); mod = 1; } @@ -3218,6 +3276,12 @@ void Fl_Widget_Type::write_widget_code(Fd_Code_Writer& f) { f.write_c("%s%s->labelsize(%d);\n", f.indent(), var, o->labelsize()); if (o->labelcolor() != tplate->labelcolor() || subclass()) write_color(f, "labelcolor", o->labelcolor()); + if (o->horizontal_label_margin() != tplate->horizontal_label_margin()) + f.write_c("%s%s->horizontal_label_margin(%d);\n", f.indent(), var, o->horizontal_label_margin()); + if (o->vertical_label_margin() != tplate->vertical_label_margin()) + f.write_c("%s%s->vertical_label_margin(%d);\n", f.indent(), var, o->vertical_label_margin()); + if (o->label_image_spacing() != tplate->label_image_spacing()) + f.write_c("%s%s->label_image_spacing(%d);\n", f.indent(), var, o->label_image_spacing()); if (is_a(ID_Valuator_)) { Fl_Valuator* v = (Fl_Valuator*)o; Fl_Valuator* t = (Fl_Valuator*)(tplate); @@ -3397,6 +3461,10 @@ void Fl_Widget_Type::write_properties(Fd_Project_Writer &f) { f.write_string("labelcolor %d", o->labelcolor()); if (o->align()!=tplate->align()) f.write_string("align %d", o->align()); + if (o->horizontal_label_margin()!=tplate->horizontal_label_margin()) + f.write_string("h_label_margin %d", o->horizontal_label_margin()); + if (o->vertical_label_margin()!=tplate->vertical_label_margin()) + f.write_string("v_label_margin %d", o->vertical_label_margin()); if (o->label_image_spacing()!=tplate->label_image_spacing()) f.write_string("image_spacing %d", o->label_image_spacing()); if (o->when() != tplate->when()) @@ -3568,6 +3636,10 @@ void Fl_Widget_Type::read_property(Fd_Project_Reader &f, const char *c) { if (sscanf(f.read_word(),"%d",&x) == 1) o->labelcolor(x); } else if (!strcmp(c,"align")) { if (sscanf(f.read_word(),"%d",&x) == 1) o->align(x); + } else if (!strcmp(c,"h_label_margin")) { + if (sscanf(f.read_word(),"%d",&x) == 1) o->horizontal_label_margin(x); + } else if (!strcmp(c,"v_label_margin")) { + if (sscanf(f.read_word(),"%d",&x) == 1) o->vertical_label_margin(x); } else if (!strcmp(c,"image_spacing")) { if (sscanf(f.read_word(),"%d",&x) == 1) o->label_image_spacing(x); } else if (!strcmp(c,"when")) { diff --git a/fluid/README_fl.txt b/fluid/README_fl.txt index 387d69f98..c52b4d091 100644 --- a/fluid/README_fl.txt +++ b/fluid/README_fl.txt @@ -468,6 +468,8 @@ Type "Fl_Widget" : C++ variable name "labelsize" : integer "labelcolor" : integer, color index "align" : integer, see Fl_Align + "h_label_margin" : integer, horizontal label margin + "v_label_margin" : integer, vertical label margin "image_spacing" : integer, see Fl_Widget::label_image_spacing() "when" : integer, see Fl_When "minimum" : (is_valuator(), is_spinner()) double diff --git a/fluid/widget_panel.cxx b/fluid/widget_panel.cxx index a54ab7bfb..4280a3fce 100644 --- a/fluid/widget_panel.cxx +++ b/fluid/widget_panel.cxx @@ -1664,23 +1664,54 @@ Fl_Double_Window* make_widget_panel() { } // Fl_Menu_Button* o wp_style_text->end(); } // Fl_Group* wp_style_text - { Fl_Value_Input* o = new Fl_Value_Input(99, 140, 49, 20, "Image Spacing:"); - o->tooltip("Gap between label image and text in pixels"); + { Fl_Group* o = new Fl_Group(99, 150, 242, 20, "Label Margin:"); o->labelfont(1); o->labelsize(11); - o->maximum(100); - o->step(1); - o->value(14); - o->textsize(11); - o->callback((Fl_Callback*)image_spacing_cb); - } // Fl_Value_Input* o - { Fl_Light_Button* o = new Fl_Light_Button(99, 165, 90, 20, "Compact"); + o->callback((Fl_Callback*)propagate_load); + o->align(Fl_Align(FL_ALIGN_LEFT)); + { Fl_Value_Input* o = new Fl_Value_Input(99, 150, 55, 20, "Horizontal:"); + o->tooltip("Spacing between label and the horizontally aligned side of the widget."); + o->labelsize(11); + o->minimum(-127); + o->maximum(128); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)h_label_margin_cb); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(159, 150, 55, 20, "Vertical:"); + o->tooltip("Spacing between label and the vertically aligned side of the widget."); + o->labelsize(11); + o->minimum(-127); + o->maximum(127); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)v_label_margin_cb); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(219, 150, 55, 20, "Text to Image:"); + o->tooltip("Gap between label image and text in pixels"); + o->labelsize(11); + o->maximum(255); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)image_spacing_cb); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(281, 150, 60, 20); + o->labelsize(11); + o->hide(); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + o->end(); + } // Fl_Group* o + { Fl_Light_Button* o = new Fl_Light_Button(99, 175, 90, 20, "Compact"); o->tooltip("use compact box types for closely set buttons"); o->selection_color((Fl_Color)1); o->labelsize(11); o->callback((Fl_Callback*)compact_cb); } // Fl_Light_Button* o - { Fl_Box* o = new Fl_Box(195, 195, 40, 40); + { Fl_Box* o = new Fl_Box(195, 205, 40, 40); o->labelsize(11); Fl_Group::current()->resizable(o); } // Fl_Box* o diff --git a/fluid/widget_panel.fl b/fluid/widget_panel.fl index e7f0b70b7..cdb5deabe 100644 --- a/fluid/widget_panel.fl +++ b/fluid/widget_panel.fl @@ -935,18 +935,37 @@ Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize code1 {o->menu(colormenu);} } {} } - Fl_Value_Input {} { - label {Image Spacing:} - callback image_spacing_cb - tooltip {Gap between label image and text in pixels} xywh {99 140 49 20} labelfont 1 labelsize 11 maximum 100 step 1 value 14 textsize 11 + Fl_Group {} { + label {Label Margin:} + callback propagate_load open + xywh {99 150 242 20} labelfont 1 labelsize 11 align 4 + } { + Fl_Value_Input {} { + label {Horizontal:} + callback h_label_margin_cb + tooltip {Spacing between label and the horizontally aligned side of the widget.} xywh {99 150 55 20} labelsize 11 align 5 minimum -127 maximum 128 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Vertical:} + callback v_label_margin_cb + tooltip {Spacing between label and the vertically aligned side of the widget.} xywh {159 150 55 20} labelsize 11 align 5 minimum -127 maximum 127 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Text to Image:} + callback image_spacing_cb + tooltip {Gap between label image and text in pixels} xywh {219 150 55 20} labelsize 11 align 5 maximum 255 step 1 textsize 11 + } + Fl_Box {} { + xywh {281 150 60 20} labelsize 11 hide resizable + } } Fl_Light_Button {} { label Compact callback compact_cb - tooltip {use compact box types for closely set buttons} xywh {99 165 90 20} selection_color 1 labelsize 11 + tooltip {use compact box types for closely set buttons} xywh {99 175 90 20} selection_color 1 labelsize 11 } Fl_Box {} { - xywh {195 195 40 40} labelsize 11 resizable + xywh {195 205 40 40} labelsize 11 resizable } } Fl_Group wp_cpp_tab { diff --git a/fluid/widget_panel.h b/fluid/widget_panel.h index 759cd9081..96022286c 100644 --- a/fluid/widget_panel.h +++ b/fluid/widget_panel.h @@ -144,6 +144,8 @@ extern void textsize_cb(Fl_Value_Input*, void*); extern void textcolor_cb(Fl_Button*, void*); extern Fl_Button *w_textcolor; extern void textcolor_menu_cb(Fl_Menu_Button*, void*); +extern void h_label_margin_cb(Fl_Value_Input*, void*); +extern void v_label_margin_cb(Fl_Value_Input*, void*); extern void image_spacing_cb(Fl_Value_Input*, void*); extern void compact_cb(Fl_Light_Button*, void*); extern Fl_Group *wp_cpp_tab; diff --git a/src/Fl_Choice.cxx b/src/Fl_Choice.cxx index 3ba0a2c7d..e5a0276af 100644 --- a/src/Fl_Choice.cxx +++ b/src/Fl_Choice.cxx @@ -113,7 +113,7 @@ void Fl_Choice::draw() { l.font = m.labelsize_ || m.labelfont_ ? m.labelfont_ : textfont(); l.size = m.labelsize_ ? m.labelsize_ : textsize(); l.color= m.labelcolor_ ? m.labelcolor_ : textcolor(); - l.spacing = 0; + l.h_margin_ = l.v_margin_ = l.spacing = 0; if (!m.active()) l.color = fl_inactive((Fl_Color)l.color); fl_draw_shortcut = 2; // hack value to make '&' disappear l.draw(xx+3, yy, ww>6 ? ww-6 : 0, hh, FL_ALIGN_LEFT); diff --git a/src/Fl_Menu.cxx b/src/Fl_Menu.cxx index 79228de80..a3a1c82e6 100644 --- a/src/Fl_Menu.cxx +++ b/src/Fl_Menu.cxx @@ -261,7 +261,7 @@ int Fl_Menu_Item::measure(int* hp, const Fl_Menu_* m) const { l.font = labelsize_ || labelfont_ ? labelfont_ : (m ? m->textfont() : FL_HELVETICA); l.size = labelsize_ ? labelsize_ : m ? m->textsize() : FL_NORMAL_SIZE; l.color = FL_FOREGROUND_COLOR; // this makes no difference? - l.spacing = 0; + l.h_margin_ = l.v_margin_ = l.spacing = 0; fl_draw_shortcut = 1; int w = 0; int h = 0; l.measure(w, hp ? *hp : h); @@ -281,7 +281,7 @@ void Fl_Menu_Item::draw(int x, int y, int w, int h, const Fl_Menu_* m, l.font = labelsize_ || labelfont_ ? labelfont_ : (m ? m->textfont() : FL_HELVETICA); l.size = labelsize_ ? labelsize_ : m ? m->textsize() : FL_NORMAL_SIZE; l.color = labelcolor_ ? labelcolor_ : m ? m->textcolor() : int(FL_FOREGROUND_COLOR); - l.spacing = 0; + l.h_margin_ = l.v_margin_ = l.spacing = 0; if (!active()) l.color = fl_inactive((Fl_Color)l.color); if (selected) { Fl_Color r = m ? m->selection_color() : FL_SELECTION_COLOR; diff --git a/src/Fl_Widget.cxx b/src/Fl_Widget.cxx index d5adb5a08..3a583ca4d 100644 --- a/src/Fl_Widget.cxx +++ b/src/Fl_Widget.cxx @@ -118,6 +118,7 @@ Fl_Widget::Fl_Widget(int X, int Y, int W, int H, const char* L) { label_.size = FL_NORMAL_SIZE; label_.color = FL_FOREGROUND_COLOR; label_.align_ = FL_ALIGN_CENTER; + label_.h_margin_ = label_.v_margin_ = 0; label_.spacing = 0; tooltip_ = 0; callback_ = default_callback; diff --git a/src/Fl_Window.cxx b/src/Fl_Window.cxx index 20a39a68e..6ded79b01 100644 --- a/src/Fl_Window.cxx +++ b/src/Fl_Window.cxx @@ -526,7 +526,7 @@ void Fl_Window::draw_backdrop() { l1.image = image(); if (!active_r() && l1.image && l1.deimage) l1.image = l1.deimage; l1.type = labeltype(); - l1.spacing = 0; + l1.h_margin_ = l1.v_margin_ = l1.spacing = 0; l1.draw(0,0,w(),h(),align()); } } diff --git a/src/fl_labeltype.cxx b/src/fl_labeltype.cxx index 9f5c5f20e..991bc5e56 100644 --- a/src/fl_labeltype.cxx +++ b/src/fl_labeltype.cxx @@ -82,6 +82,29 @@ void Fl::set_labeltype(Fl_Labeltype t,Fl_Label_Draw_F* f,Fl_Label_Measure_F*m) /** Draws a label with arbitrary alignment in an arbitrary box. */ void Fl_Label::draw(int X, int Y, int W, int H, Fl_Align align) const { if (!value && !image) return; + const Fl_Align FL_ALIGN_CENTER = 0x0000; + const Fl_Align FL_ALIGN_TOP = 0x0001; + const Fl_Align FL_ALIGN_BOTTOM = 0x0002; + const Fl_Align FL_ALIGN_LEFT = 0x0004; + const Fl_Align FL_ALIGN_RIGHT = 0x0008; + const Fl_Align FL_ALIGN_TOP_LEFT = FL_ALIGN_TOP | FL_ALIGN_LEFT; + const Fl_Align FL_ALIGN_TOP_RIGHT = FL_ALIGN_TOP | FL_ALIGN_RIGHT; + const Fl_Align FL_ALIGN_BOTTOM_LEFT = FL_ALIGN_BOTTOM | FL_ALIGN_LEFT; + const Fl_Align FL_ALIGN_BOTTOM_RIGHT = FL_ALIGN_BOTTOM | FL_ALIGN_RIGHT; + const Fl_Align FL_ALIGN_LEFT_TOP = 0x0007; + const Fl_Align FL_ALIGN_RIGHT_TOP = 0x000b; + const Fl_Align FL_ALIGN_LEFT_BOTTOM = 0x000d; + const Fl_Align FL_ALIGN_RIGHT_BOTTOM = 0x000e; + switch (align&(FL_ALIGN_TOP|FL_ALIGN_BOTTOM)) { + case 0: Y += v_margin_; H -= 2*v_margin_; break; + case FL_ALIGN_TOP: Y += v_margin_; H -= v_margin_; break; + case FL_ALIGN_BOTTOM: H -= v_margin_; break; + } + switch (align&(FL_ALIGN_LEFT|FL_ALIGN_RIGHT)) { + case 0: X += h_margin_; W -= 2*h_margin_; break; + case FL_ALIGN_LEFT: X += h_margin_; W -= h_margin_; break; + case FL_ALIGN_RIGHT: W -= h_margin_; break; + } table[type](this, X, Y, W, H, align); } /** @@ -95,6 +118,7 @@ void Fl_Label::measure(int& W, int& H) const { return; } +// if (W > 0) W -= h_margin_; Fl_Label_Measure_F* f = ::measure[type]; if (!f) f = fl_normal_measure; f(this, W, H); } diff --git a/test/label.cxx b/test/label.cxx index de88b976b..f155132eb 100644 --- a/test/label.cxx +++ b/test/label.cxx @@ -32,7 +32,7 @@ Fl_Box *text; Fl_Input *input; Fl_Hor_Value_Slider *fonts; Fl_Hor_Value_Slider *sizes; -Fl_Hor_Value_Slider *spacing; +Fl_Hor_Value_Slider *h_margin, *v_margin, *img_spacing; Fl_Double_Window *window; Fl_Pixmap *img; @@ -65,8 +65,18 @@ void font_cb(Fl_Widget *,void *) { window->redraw(); } +void h_margin_cb(Fl_Widget *,void *) { + text->horizontal_label_margin(int(h_margin->value())); + window->redraw(); +} + +void v_margin_cb(Fl_Widget *,void *) { + text->vertical_label_margin(int(v_margin->value())); + window->redraw(); +} + void spacing_cb(Fl_Widget *,void *) { - text->label_image_spacing(int(spacing->value())); + text->label_image_spacing(int(img_spacing->value())); window->redraw(); } @@ -120,9 +130,9 @@ Fl_Menu_Item choices[] = { int main(int argc, char **argv) { img = new Fl_Pixmap(blast_xpm); - window = new Fl_Double_Window(440,445); + window = new Fl_Double_Window(440,495); - input = new Fl_Input(70,400,350,25,"Label:"); + input = new Fl_Input(70,435,350,25,"Label:"); input->static_value("The quick brown fox jumped over the lazy dog."); input->when(FL_WHEN_CHANGED); input->callback(input_cb); @@ -142,12 +152,30 @@ int main(int argc, char **argv) { fonts->value(0); fonts->callback(font_cb); - spacing=new Fl_Hor_Value_Slider(70,375,350,25,"Spacing:"); - spacing->align(FL_ALIGN_LEFT); - spacing->bounds(0,100); - spacing->step(1); - spacing->value(0); - spacing->callback(spacing_cb); + Fl_Box *margin = new Fl_Box(0, 380, 70, 25, "Margins"); + margin->box(FL_FLAT_BOX); + margin->align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE); + + h_margin = new Fl_Hor_Value_Slider(70+50,380,125,25,"Hor:"); + h_margin->align(FL_ALIGN_LEFT); + h_margin->bounds(-25,25); + h_margin->step(1); + h_margin->value(0); + h_margin->callback(h_margin_cb); + + v_margin = new Fl_Hor_Value_Slider(70+175+50,380,125,25,"Vert:"); + v_margin->align(FL_ALIGN_LEFT); + v_margin->bounds(-25,25); + v_margin->step(1); + v_margin->value(0); + v_margin->callback(v_margin_cb); + + img_spacing = new Fl_Hor_Value_Slider(70+50,405,125,25,"Image:"); + img_spacing->align(FL_ALIGN_LEFT); + img_spacing->bounds(0,50); + img_spacing->step(1); + img_spacing->value(0); + img_spacing->callback(spacing_cb); Fl_Group *g = new Fl_Group(70,275,350,50); imageb = new Fl_Toggle_Button(70,275,50,25,"image");