From b18314ef23be002fbd6a2d8bd8633b8d4bfe33c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=28=C2=B4=E3=83=BB=CF=89=E3=83=BB=EF=BD=80=29?= Date: Fri, 26 Jul 2024 19:59:16 +0900 Subject: [PATCH] CHG: overhaul of depotlist doalog --- gui/depotlist_frame.cc | 449 +++++++++++++++++++---------------------- gui/depotlist_frame.h | 96 +++++---- simdepot.cc | 5 + 3 files changed, 275 insertions(+), 275 deletions(-) diff --git a/gui/depotlist_frame.cc b/gui/depotlist_frame.cc index e933a49535..3e28d37230 100644 --- a/gui/depotlist_frame.cc +++ b/gui/depotlist_frame.cc @@ -10,7 +10,6 @@ #include "../player/simplay.h" #include "../simcity.h" -#include "../simdepot.h" #include "../simskin.h" #include "../simworld.h" @@ -25,248 +24,193 @@ #include "../boden/wege/strasse.h" #include "../bauer/vehikelbauer.h" -enum sort_mode_t { by_name, by_waytype, by_convoys, by_vehicle, by_coord, by_region, SORT_MODES }; +#include "../descriptor/building_desc.h" +#include "../display/viewport.h" + +static const char* const dl_header_text[depotlist_row_t::MAX_COLS] = +{ + "", "Name", "convoys stored", "vehicles stored", "koord", "by_region", "City", "Fixed Costs", "Built in" +}; + +int depotlist_row_t::sort_mode = 0; +bool depotlist_row_t::sortreverse = false; + -uint8 depotlist_stats_t::sort_mode = by_name; -bool depotlist_stats_t::reverse = false; -uint16 depotlist_stats_t::name_width = D_LABEL_WIDTH; uint8 depotlist_frame_t::selected_tab = 0; static karte_ptr_t welt; -bool depotlist_frame_t::is_available_wt(waytype_t wt) + +depot_type_cell_t::depot_type_cell_t(obj_t::typ typ, bool is_electrified) : values_cell_t((sint64)typ, (sint64)is_electrified, SYSCOL_TEXT, true) { - switch (wt) { - case maglev_wt: - return maglev_t::default_maglev ? true : false; - case monorail_wt: - return monorail_t::default_monorail ? true : false; - case track_wt: - return schiene_t::default_schiene ? true : false; - case tram_wt: - return vehicle_builder_t::get_info(tram_wt).empty() ? false : true; - case narrowgauge_wt: - return narrowgauge_t::default_narrowgauge ? true : false; - case road_wt: - return strasse_t::default_strasse ? true : false; - case water_wt: - return vehicle_builder_t::get_info(water_wt).empty() ? false : true; - case air_wt: - return runway_t::default_runway ? true : false; - default: - return false; - } - return false; + align = centered; + min_size = scr_size(D_FIXED_SYMBOL_WIDTH + LINESPACE, ((LINESPACE-2)*2/3-1)); + color = minimap_t::get_depot_color(typ); + + set_size(min_size); } -depotlist_stats_t::depotlist_stats_t(depot_t *d) +void depot_type_cell_t::draw(scr_coord offset) { - this->depot = d; - set_table_layout(7,1); - new_component(0); - const waytype_t wt = d->get_wegtyp(); + table_cell_item_t::draw(offset); - const weg_t *w = welt->lookup(depot->get_pos())->get_weg(wt != tram_wt ? wt : track_wt); - const bool way_electrified = w ? w->is_electrified() : false; - if (way_electrified) { - new_component()->set_image(skinverwaltung_t::electricity->get_image_id(0), true); - } - else { - new_component(skinverwaltung_t::electricity->get_image(0)->w); - } - - lb_name.buf().append( translator::translate(depot->get_name()) ); - const scr_coord_val temp_w = proportional_string_width( translator::translate(depot->get_name()) ); - if (temp_w > name_width) { - name_width = temp_w; - } - lb_name.set_fixed_width(name_width); - add_component(&lb_name); + offset += pos; - lb_cnv_count.init(SYSCOL_TEXT, gui_label_t::right); - lb_cnv_count.set_fixed_width(proportional_string_width(translator::translate("%d convois"))); - add_component(&lb_cnv_count); - lb_vh_count.init(SYSCOL_TEXT, gui_label_t::right); - lb_vh_count.set_fixed_width(proportional_string_width(translator::translate("%d vehicles"))); - add_component(&lb_vh_count); + display_depot_symbol_rgb(offset.x + draw_offset.x, offset.y + draw_offset.y-1, LINESPACE-2, color, false); - add_table(2,1)->set_spacing(scr_size(0,0)); - { - // pos button (depot type) - //// Change the symbol size in the button depending on the depot level - ////const uint8 symbol_width = LINEASCENT-2 + min(2,d->get_tile()->get_desc()->get_level()/3)*2; - //gotopos.set_typ(button_t::posbutton_automatic); - gotopos.set_typ(button_t::depot_automatic); - gotopos.set_targetpos3d(depot->get_pos()); - gotopos.text_color = minimap_t::get_depot_color(depot->get_typ()); - add_component(&gotopos); - - lb_region.buf().printf( " %s ", depot->get_pos().get_2d().get_fullstr() ); - stadt_t* c = welt->get_city(depot->get_pos().get_2d()); - if (c) { - lb_region.buf().append("- "); - lb_region.buf().append( c->get_name() ); - } - if (!welt->get_settings().regions.empty()) { - if (!c) { - lb_region.buf().append("-"); - } - lb_region.buf().printf(" (%s)", translator::translate(welt->get_region_name(depot->get_pos().get_2d()).c_str())); - } - lb_region.update(); - add_component(&lb_region); + if (sub_value) { + display_color_img(skinverwaltung_t::electricity->get_image_id(0), offset.x + draw_offset.x + LINESPACE+2, offset.y + draw_offset.y + (LINESPACE * 2 / 3 - 1)/2 - D_FIXED_SYMBOL_WIDTH/2, 0, false, false); } - end_table(); - update_label(); - - new_component(); } - -void depotlist_stats_t::update_label() +depotlist_row_t::depotlist_row_t(depot_t *dep) { - lb_cnv_count.buf().clear(); - int cnvs = depot->convoi_count(); - if( cnvs == 0 ) { -// buf.append( translator::translate( "no convois" ) ); - } - else if( cnvs == 1 ) { - lb_cnv_count.buf().append( translator::translate( "1 convoi" ) ); - } - else { - lb_cnv_count.buf().printf( translator::translate( "%d convois" ), cnvs ); - } - lb_cnv_count.update(); + assert(depot!=NULL); + depot = dep; - int vhls = depot->get_vehicle_list().get_count(); - lb_vh_count.buf().clear(); - if( vhls == 0 ) { - //buf.append( translator::translate( "Keine Einzelfahrzeuge im Depot" ) ); - } - else if( vhls == 1 ) { - lb_vh_count.buf().append( translator::translate( "1 vehicle" ) ); - } - else { - lb_vh_count.buf().printf( translator::translate( "%d vehicles" ), vhls ); - } - if(uint32 for_sale_cnt=depot->get_vehicles_for_sale().get_count()){ - lb_vh_count.buf().printf("(%u)", for_sale_cnt); + // 1. type + const waytype_t wt = depot->get_wegtyp(); + const weg_t* w = welt->lookup(depot->get_pos())->get_weg(wt != tram_wt ? wt : track_wt); + const bool way_electrified = w ? w->is_electrified() : false; + new_component(depot->get_typ(), way_electrified); + // 2. name + new_component(depot->get_name()); + // 3. convoys + old_convoys = depot->get_convoy_list().get_count(); + new_component((sint64)old_convoys, gui_chart_t::STANDARD, table_cell_item_t::right, old_convoys ? SYSCOL_TEXT : SYSCOL_TEXT_INACTIVE); + // 4. vehicle count and listed count + const sint64 listed_vehicles = (sint64)depot->get_vehicles_for_sale().get_count(); + old_vehicles = depot->get_vehicle_list().get_count(); + new_component((sint64)old_vehicles+listed_vehicles, listed_vehicles, SYSCOL_TEXT, true); + // 5. pos + const koord depot_pos = depot->get_pos().get_2d(); + new_component(depot_pos, table_cell_item_t::centered); + // 6. region + new_component(welt->get_settings().regions.empty() ? "" : translator::translate(welt->get_region_name(depot_pos).c_str())); + // 7. city + stadt_t* c = welt->get_city(depot_pos); + new_component(c ? c->get_name() : "-", c ? c->get_center(): koord::invalid); + // 8. Fixed Costs + sint64 maintenance = depot->get_tile()->get_desc()->get_maintenance(); + if (maintenance == PRICE_MAGIC) + { + maintenance = depot->get_tile()->get_desc()->get_level() * welt->get_settings().maint_building; } + new_component((double)welt->calc_adjusted_monthly_figure(maintenance), gui_chart_t::MONEY, table_cell_item_t::right); + // 9. Built date + new_component((sint64)depot->get_purchase_time(), gui_chart_t::DATE, table_cell_item_t::right); - lb_vh_count.update(); -} + // Possibility of adding items: + // supported traction types + // init cells height + for (auto& cell : owned_cells) { + cell->set_height(row_height); + } -void depotlist_stats_t::set_size(scr_size size) -{ - gui_aligned_container_t::set_size(size); } - -bool depotlist_stats_t::is_valid() const +void depotlist_row_t::draw(scr_coord offset) { - return depot_t::get_depot_list().is_contained(depot); + if (old_convoys != depot->get_convoy_list().get_count()) { + value_cell_t *cell = dynamic_cast(owned_cells[DEPOT_CONVOYS]); + old_convoys = depot->get_convoy_list().get_count(); + cell->set_value((sint64)old_convoys); + cell->set_color(old_convoys ? SYSCOL_TEXT : SYSCOL_TEXT_INACTIVE); + } + if (old_vehicles != depot->get_vehicle_list().get_count()) { + values_cell_t* cell = dynamic_cast(owned_cells[DEPOT_VEHICLES]); + old_vehicles = depot->get_vehicle_list().get_count(); + cell->set_values((sint64)old_vehicles, (sint64)depot->get_vehicles_for_sale().get_count()); + } + gui_sort_table_row_t::draw(offset); } - -bool depotlist_stats_t::infowin_event(const event_t * ev) +void depotlist_row_t::show_depot() { - bool swallowed = gui_aligned_container_t::infowin_event(ev); - - if( !swallowed && IS_LEFTRELEASE(ev) ) { + if (depot->get_owner() == world()->get_active_player() ) { depot->show_info(); - swallowed = true; } - return swallowed; -} - - -void depotlist_stats_t::draw(scr_coord pos) -{ - update_label(); - - gui_aligned_container_t::draw(pos); } -bool depotlist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb) +bool depotlist_row_t::infowin_event(const event_t* ev) { - const depotlist_stats_t* fa = dynamic_cast(aa); - const depotlist_stats_t* fb = dynamic_cast(bb); - // good luck with mixed lists - assert(fa != NULL && fb != NULL); - depot_t *a=fa->depot, *b=fb->depot; - - int cmp; - switch( sort_mode ) { - default: - case by_coord: - cmp = 0; - break; - - case by_region: - cmp = welt->get_region(a->get_pos().get_2d()) - welt->get_region(b->get_pos().get_2d()); - if (cmp == 0) { - const koord a_city_koord = welt->get_city(a->get_pos().get_2d()) ? welt->get_city(a->get_pos().get_2d())->get_pos() : koord(0, 0); - const koord b_city_koord = welt->get_city(b->get_pos().get_2d()) ? welt->get_city(b->get_pos().get_2d())->get_pos() : koord(0, 0); - cmp = a_city_koord.x - b_city_koord.x; - if (cmp == 0) { - cmp = a_city_koord.y - b_city_koord.y; + bool swallowed = gui_scrolled_list_t::scrollitem_t::infowin_event(ev); + + if (!swallowed && depot) { + if (IS_RIGHTRELEASE(ev)) { + for (auto& cell : owned_cells) { + if (cell->get_type() == table_cell_item_t::cell_coord && cell->getroffen(ev->mouse_pos)) { + const coord_cell_t* coord_cell = dynamic_cast(cell); + const koord k = coord_cell->get_coord(); + if (k != koord::invalid) { + world()->get_viewport()->change_world_position(k); + return true; + } + return false; + } } } - break; - - case by_name: - cmp = strcmp(a->get_name(), b->get_name()); - break; - - case by_waytype: - cmp = a->get_waytype() - b->get_waytype(); - if (cmp == 0) { - cmp = strcmp(a->get_name(), b->get_name()); - } - break; + } + return swallowed; +} - case by_convoys: - cmp = a->convoi_count() - b->convoi_count(); - if( cmp == 0 ) { - cmp = a->get_vehicle_list().get_count() - b->get_vehicle_list().get_count(); - } - break; - case by_vehicle: - cmp = a->get_vehicle_list().get_count() - b->get_vehicle_list().get_count(); - if( cmp == 0 ) { - cmp = a->convoi_count() - b->convoi_count(); - } - break; +bool depotlist_row_t::compare(const gui_component_t* aa, const gui_component_t* bb) +{ + const depotlist_row_t* row_a = dynamic_cast(aa); + const depotlist_row_t* row_b = dynamic_cast(bb); + if (row_a == NULL || row_b == NULL) { + dbg->warning("depotlist_row_t::compare()", "row data error"); + return false; } - if (cmp == 0) { - cmp = koord_distance( a->get_pos(), koord( 0, 0 ) ) - koord_distance( b->get_pos(), koord( 0, 0 ) ); - if( cmp == 0 ) { - cmp = a->get_pos().x - b->get_pos().x; - } + + const table_cell_item_t* a = row_a->get_element(sort_mode); + const table_cell_item_t* b = row_b->get_element(sort_mode); + if (a == NULL || b == NULL) { + dbg->warning("depotlist_row_t::compare()", "Could not get table_cell_item_t successfully"); + return false; } - return reverse ? cmp > 0 : cmp < 0; + + int cmp = gui_sort_table_row_t::compare(a, b); + return sortreverse ? cmp < 0 : cmp > 0; // Do not include 0 } +bool depotlist_frame_t::is_available_wt(waytype_t wt) +{ + switch (wt) { + case maglev_wt: + return maglev_t::default_maglev ? true : false; + case monorail_wt: + return monorail_t::default_monorail ? true : false; + case track_wt: + return schiene_t::default_schiene ? true : false; + case tram_wt: + return vehicle_builder_t::get_info(tram_wt).empty() ? false : true; + case narrowgauge_wt: + return narrowgauge_t::default_narrowgauge ? true : false; + case road_wt: + return strasse_t::default_strasse ? true : false; + case water_wt: + return vehicle_builder_t::get_info(water_wt).empty() ? false : true; + case air_wt: + return runway_t::default_runway ? true : false; + default: + return false; + } + return false; +} -static const char *sort_text[SORT_MODES] = { - "hl_btn_sort_name", - "waytype", - "convoys stored", - "vehicles stored", - "koord", - "by_region" -}; depotlist_frame_t::depotlist_frame_t(player_t *player) : gui_frame_t( translator::translate("dp_title"), player ), - scrolly(gui_scrolled_list_t::windowskin, depotlist_stats_t::compare) + scrolly(gui_scrolled_list_t::windowskin, depotlist_row_t::compare), + scroll_tab(&cont_sortable, true, false) { this->player = player; @@ -276,7 +220,8 @@ depotlist_frame_t::depotlist_frame_t(player_t *player) : depotlist_frame_t::depotlist_frame_t() : gui_frame_t(translator::translate("dp_title"), NULL), - scrolly(gui_scrolled_list_t::windowskin, depotlist_stats_t::compare) + scrolly(gui_scrolled_list_t::windowskin, depotlist_row_t::compare), + scroll_tab(&cont_sortable, true, false) { player = NULL; @@ -288,48 +233,38 @@ void depotlist_frame_t::init_table() { last_depot_count = 0; - set_table_layout(1,0); + scrolly.add_listener(this); + scrolly.set_show_scroll_x(false); + scrolly.set_checkered(true); + scrolly.set_scroll_amount_y(LINESPACE + D_H_SPACE + 2); // default cell height - add_table(3,1); - { - new_component("hl_txt_sort"); - add_table(3,1); - { - sortedby.clear_elements(); - for (int i = 0; i < SORT_MODES; i++) { - sortedby.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT); - } - sortedby.set_selection(depotlist_stats_t::sort_mode); - sortedby.add_listener(this); - sortedby.set_width_fixed(true); - sortedby.set_width(LINESPACE*12); - add_component(&sortedby); - - // sort asc/desc switching button - sort_order.init(button_t::sortarrow_state, ""); - sort_order.set_tooltip(translator::translate("hl_btn_sort_order")); - sort_order.add_listener(this); - sort_order.pressed = depotlist_stats_t::reverse; - add_component(&sort_order); - - new_component(D_H_SPACE*2); - } - end_table(); + scroll_tab.set_maximize(true); - lb_depot_counter.set_fixed_width(proportional_string_width("8888/8888")); - add_component(&lb_depot_counter); + // init table sort buttons + table_header.add_listener(this); + for (uint8 col = 0; col < depotlist_row_t::MAX_COLS; col++) { + table_header.new_component(dl_header_text[col]); } - end_table(); - tabs.init_tabs(&scrolly); + cont_sortable.set_margin(NO_SPACING, NO_SPACING); + cont_sortable.set_spacing(NO_SPACING); + cont_sortable.set_table_layout(1, 2); + cont_sortable.set_alignment(ALIGN_TOP); // Without this, the layout will be broken if the height is small. + cont_sortable.add_component(&table_header); + cont_sortable.add_component(&scrolly); + + set_table_layout(1,0); + + lb_depot_counter.set_fixed_width(proportional_string_width("8888/8888")); + add_component(&lb_depot_counter); + + tabs.init_tabs(&scroll_tab); tabs.add_listener(this); add_component(&tabs); + set_min_windowsize(scr_size(LINESPACE*24, LINESPACE*12)); fill_list(); set_resizemode(diagonal_resize); - scrolly.set_maximize(true); - scrolly.set_checkered(true); - reset_min_windowsize(); } /** @@ -340,15 +275,18 @@ bool depotlist_frame_t::action_triggered( gui_action_creator_t *comp,value_t v) if (comp == &tabs) { fill_list(); } - else if(comp == &sortedby) { - depotlist_stats_t::sort_mode = max(0, v.i); + else if (comp == &table_header) { + depotlist_row_t::sort_mode = v.i; + table_header.set_selection(depotlist_row_t::sort_mode); + depotlist_row_t::sortreverse = table_header.is_reversed(); scrolly.sort(0); } - else if (comp == &sort_order) { - depotlist_stats_t::reverse = !depotlist_stats_t::reverse; - scrolly.sort(0); - sort_order.pressed = depotlist_stats_t::reverse; + else if ( comp == &scrolly ) { + scrolly.get_selection(); + depotlist_row_t* row = (depotlist_row_t*)scrolly.get_element(v.i); + row->show_depot(); } + return true; } @@ -360,7 +298,7 @@ void depotlist_frame_t::fill_list() for(depot_t* const depot : depot_t::get_depot_list()) { if( depot->get_owner() == player ) { if( tabs.get_active_tab_index() == 0 || depot->get_waytype() == tabs.get_active_tab_waytype() ) { - scrolly.new_component(depot); + scrolly.new_component(depot); } p_total++; } @@ -370,6 +308,39 @@ void depotlist_frame_t::fill_list() scrolly.sort(0); scrolly.set_size(scr_size(get_windowsize().w, scrolly.get_size().h)); + // recalc stats table width + scr_coord_val max_widths[depotlist_row_t::MAX_COLS] = {}; + + // check column widths + table_header.set_selection(depotlist_row_t::sort_mode); + table_header.set_width(D_H_SPACE); // init width + for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) { + // get header widths + max_widths[c] = table_header.get_min_width(c); + } + for (int r = 0; r < scrolly.get_count(); r++) { + depotlist_row_t* row = (depotlist_row_t*)scrolly.get_element(r); + for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) { + max_widths[c] = max(max_widths[c], row->get_min_width(c)); + } + } + + // set column widths + for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) { + table_header.set_col(c, max_widths[c]); + } + table_header.set_width(table_header.get_size().w + D_SCROLLBAR_WIDTH); + + for (int r = 0; r < scrolly.get_count(); r++) { + depotlist_row_t* row = (depotlist_row_t*)scrolly.get_element(r); + row->set_size(scr_size(0, row->get_size().h)); + for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) { + row->set_col(c, max_widths[c]); + } + } + + cont_sortable.set_size(cont_sortable.get_min_size()); + last_depot_count = depot_t::get_depot_list().get_count(); resize(scr_coord(0, 0)); } @@ -392,8 +363,8 @@ void depotlist_frame_t::rdwr(loadsave_t *file) selected_tab = tabs.get_active_tab_index(); file->rdwr_byte(selected_tab); - file->rdwr_bool(sort_order.pressed); - uint8 s = depotlist_stats_t::sort_mode; + file->rdwr_bool(depotlist_row_t::sortreverse); + uint8 s = (uint8)depotlist_row_t::sort_mode; file->rdwr_byte(s); file->rdwr_byte(player_nr); size.rdwr(file); @@ -402,9 +373,7 @@ void depotlist_frame_t::rdwr(loadsave_t *file) player = welt->get_player(player_nr); gui_frame_t::set_owner(player); win_set_magic(this, magic_depotlist + player_nr); - sortedby.set_selection(s); - depotlist_stats_t::sort_mode = s; - depotlist_stats_t::reverse = sort_order.pressed; + depotlist_row_t::sort_mode = (int)s; tabs.set_active_tab_index(selected_tabget_name(); } + + void show_depot(); + + bool infowin_event(event_t const* ev) OVERRIDE; + + void draw(scr_coord offset) OVERRIDE; + + static bool compare(const gui_component_t* aa, const gui_component_t* bb); +}; + class depotlist_frame_t : public gui_frame_t, private action_listener_t { private: - gui_combobox_t sortedby; - button_t sort_order; + gui_sort_table_header_t table_header; + gui_aligned_container_t cont_sortable; gui_scrolled_list_t scrolly; + gui_scrollpane_t scroll_tab; + gui_label_buf_t lb_depot_counter; gui_waytype_tab_panel_t tabs; @@ -33,8 +90,6 @@ class depotlist_frame_t : public gui_frame_t, private action_listener_t uint32 last_depot_count; static uint8 selected_tab; - void fill_list(); - void init_table(); player_t *player; @@ -46,6 +101,8 @@ class depotlist_frame_t : public gui_frame_t, private action_listener_t const char *get_help_filename() const OVERRIDE {return "depotlist.txt"; } + void fill_list(); + bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void draw(scr_coord pos, scr_size size) OVERRIDE; @@ -62,35 +119,4 @@ class depotlist_frame_t : public gui_frame_t, private action_listener_t }; -class depotlist_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t -{ -private: - depot_t *depot; - gui_label_buf_t - lb_name, - lb_cnv_count, - lb_vh_count, - lb_region; - gui_image_t waytype_symbol; - button_t gotopos; - - void update_label(); - -public: - static uint8 sort_mode; - static bool reverse; - static uint16 name_width; - - depotlist_stats_t(depot_t *); - - void draw( scr_coord pos) OVERRIDE; - - char const* get_text() const OVERRIDE { return ""; /* label.buf().get_str(); */ } - bool infowin_event(const event_t *) OVERRIDE; - bool is_valid() const OVERRIDE; - void set_size(scr_size size) OVERRIDE; - - static bool compare(const gui_component_t *a, const gui_component_t *b ); -}; - #endif diff --git a/simdepot.cc b/simdepot.cc index a5321524d7..fff10d96b5 100644 --- a/simdepot.cc +++ b/simdepot.cc @@ -22,6 +22,7 @@ #include "gui/depot_frame.h" #include "gui/messagebox.h" +#include "gui/depotlist_frame.h" #include "dataobj/schedule.h" #include "dataobj/loadsave.h" @@ -850,6 +851,10 @@ void depot_t::set_name(const char* value) if (win) { win->reset_depot_name(); } + depotlist_frame_t *win2 = dynamic_cast(win_get_magic(magic_depotlist+get_owner_nr())); + if (win2) { + win2->fill_list(); + } } const char* depot_t::get_name() const