Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2003:
[Freeciv-Dev] (PR#7125) [FS] Widget set
Home

[Freeciv-Dev] (PR#7125) [FS] Widget set

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#7125) [FS] Widget set
From: "Raimar Falke" <i-freeciv-lists@xxxxxxxxxxxxx>
Date: Sat, 20 Dec 2003 11:13:31 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=7125 >


The FS client comes with its own widget set. Reason here is that the
other widget sets doesn't have the required features (alpha blending,
backend at least as generic as SDL, use of graphics for the elements,
...).

The widget set (lacking a better name I named it SW for Simple
Widgets) is declared in widget.h (attached). Everything is a widget. A
window is a widget. A window can contain other widgets. There is a
root window. Windows can have transparency. Windows can be dragged
around. This is disabled for the root window ;).

All widgets determine their size at construction time. Either
indirectly via the passed information (the size of a string for
example) or directly by specifying width and height. Almost all
widgets (only one obscure exception) don't change their size after
construction. All widgets have common properties like position, size,
tooltip, background color, background sprite, border width and border
color. So you can for example give a label widget a tooltip just
because it is fun. In addition there may be an key associated with
each widget in the future.

The widget set is clean. No user code can look into it. struct
sw_widget is an abstract type. The definition is placed in widget_p.h
(attached). The p stands here for private. All function names are of
the form sw_<widget-name>_<action>_<rest>.

Implemented widgets are window, button (with string and/or sprite),
edit, label, list and slider. Note that there are almost no
free/destroy functions. Memory leaks all over the place.

Each window has an OSDA as a backing store. In addition there is
another OSDA with the size of the screen. All non-window widgets are
drawn into the OSDA of their window. All windows are drawn into this
extra OSDA. This may involve transparency. This extra ODSA is then
drawn to the screen.

All changes which may change the appearance of the widget or its
parent (a widget is moved for example) are not immediately drawn. Only
a flag needs_redrawing is set. The clou here is when sw_paint_all (the
function which draws everything which needs redrawing) is called. One
solution would be to place before or after the be_next_event function
in the mail loop. It turns out that this is safe but slow. The
be_next_event looks like this:

  if(x11_event_availble) 
    return it;
  else
    wait for x11 socket, server socket and timeout with select

Now the sw_paint_all is moved to after the "else" above, before the
wait. This means that the screen is only updated if there are no new
x11 events. This makes the dragging of transparent windows (the
slowest operation) non-lagging (which it was before). So for each
mouse_motion event (and you will get a lot of these) only the position
of the window is updated. This is quite fast.

A problem of other widget sets is that you spend writing multiple
thousand lines to get the GTK city dialog. I think this can be
shortened. I'm not sure how it could be done but it is a goal. Either
the preprocessor is used a great time or the information is read and
parsed at runtime or a code generator generates SW-C code from some
denser definition file.

Some sample code to give you a feeling:

  connect_window = sw_window_create_by_clone(root_window);
  sw_widget_set_position(connect_window, 0, 0);

  sw_widget_set_background_sprite(connect_window, theme.intro);

  string = ct_string_create(STYLE_NORMAL, 25,
                            ct_extend_std_color(COLOR_STD_BLACK),
                            COLOR_EXT_BLUE, _("Connect"));

  button = sw_button_create(connect_window, string, theme.button.ok, NULL,
                            theme.button_background);
  sw_widget_set_position(button, 0, 400);
  sw_widget_hcenter(button);
  sw_button_set_callback(button, connect_callback, NULL);

Open points:
 - more possibilities to decorate a widget
 - remove the tilting of the background-graphics. More on this in the
 freeciv style issue.

        Raimar

-- 
 email: rf13@xxxxxxxxxxxxxxxxx
 "Reality? That's where the pizza delivery guy comes from!"

/********************************************************************** 
 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/

#ifndef FC__WIDGET_H
#define FC__WIDGET_H

struct Sprite;
struct sw_widget;

#define SPECLIST_TAG widget
#define SPECLIST_TYPE struct sw_widget
#include "speclist.h"

#define widget_list_iterate(list, item) \
    TYPED_LIST_ITERATE(struct sw_widget, list, item)
#define widget_list_iterate_end  LIST_ITERATE_END

/* Widget Types */
enum widget_type {
  WT_WINDOW,
  WT_BUTTON,
  WT_EDIT,
  WT_LABEL,
  WT_LIST,
  WT_CLIST,
  WT_SLIDER
};

enum ws_alignment {
  A_N, A_S, A_W, A_E,
  A_NC, A_SC, A_WC, A_EC,
  A_NW, A_NE, A_SW, A_SE,
  A_NS, A_WE, A_CENTER
};

#include "common_types.h"
#include "back_end.h"

/* ===== widget ==== */
enum widget_type sw_widget_get_type(const struct sw_widget *widget);
void sw_widget_set_position(struct sw_widget *widget, int x, int y);
void sw_widget_get_bounds(struct sw_widget *widget, struct ct_rect *bounds);
void sw_widget_align(struct sw_widget *widget, enum ws_alignment alignment);
void sw_widget_set_tooltip(struct sw_widget *widget, char *tooltip);
void sw_widget_hcenter(struct sw_widget *widget);
void sw_widget_vcenter(struct sw_widget *widget);
void sw_widget_set_background_sprite(struct sw_widget *widget,
                                     struct Sprite *sprite);
void sw_widget_set_background_color(struct sw_widget *widget,
                                    enum color_ext background_color);
void sw_widget_set_border_color(struct sw_widget *widget,
                                enum color_ext border_color);
void sw_widget_destroy(struct sw_widget *widget);
void sw_widget_set_passive(struct sw_widget *widget, bool passive);

/* ===== window ==== */
struct sw_widget *sw_window_create(struct sw_widget *parent, int width,
                                   int height, struct ct_string *title,
                                   int transparency, bool has_border);
struct sw_widget *sw_window_create_by_clone(struct sw_widget *widget);

void sw_window_add(struct sw_widget *window, struct sw_widget *widget);
void sw_window_remove(struct sw_widget *widget);
void sw_window_resize(struct sw_widget *widget, int width, int height);
void sw_window_set_depth(struct sw_widget *widget, int depth);
void sw_window_set_canvas_background(struct sw_widget *widget, bool yes);
struct osda *sw_window_get_canvas_background(struct sw_widget *widget);
void sw_window_set_mouse_press_notify(struct sw_widget *widget,
                                      void (*callback) (struct sw_widget *
                                                        widget,
                                                        const struct ct_point
                                                        * pos, int button, int 
state,
                                                        void *data),
                                      void *data);
void sw_window_canvas_background_region_needs_repaint(struct sw_widget
                                                      *widget,
                                                      const struct ct_rect
                                                      *region);

/* ===== button ==== */
struct sw_widget *sw_button_create(struct sw_widget *parent,
                                   struct ct_string *string,
                                   struct Sprite *sprite_faces,
                                   struct Sprite *sprite_non_faces,
                                   struct Sprite *background_faces);
struct sw_widget *sw_button_create_text(struct sw_widget *parent,
                                        struct ct_string *string);
void sw_button_set_callback(struct sw_widget *widget,
                            void (*callback) (struct sw_widget * widget,
                                              void *data), void *data);

/* ===== edit ==== */
struct sw_widget *sw_edit_create(struct sw_widget *parent,int max_size,
                                 struct ct_string *temp_and_initial_text);
/* static buffer */
const char *sw_edit_get_text(struct sw_widget *widget);

/* ===== label ==== */
struct sw_widget *sw_label_create_text(struct sw_widget *parent,
                                       struct ct_string *string);

/* ===== list ==== */
struct sw_widget *sw_list_create(struct sw_widget *parent, int pixel_width,
                                 int pixel_height);
void sw_list_clear(struct sw_widget *widget);
void sw_list_set_item(struct sw_widget *widget, int column, int row,
                      struct sw_widget *item);
void sw_list_get_view_size(struct sw_widget *widget, struct ct_size *size);
void sw_list_get_window_size(struct sw_widget *widget,struct ct_size *size);
void sw_list_get_offset(struct sw_widget *widget, struct ct_point *pos);
void sw_list_set_offset(struct sw_widget *widget, const struct ct_point *pos);
void sw_list_set_selected_row(struct sw_widget *widget, int row, bool show);
int sw_list_get_selected_row(struct sw_widget *widget);
void sw_list_set_row_enabled(struct sw_widget *widget, int row, bool enabled);
bool sw_list_is_row_enabled(struct sw_widget *widget, int row);
void sw_list_add_buttons_and_vslider(struct sw_widget *widget,
                                     struct Sprite *up, struct Sprite *down,
                                     struct Sprite *button_background,
                                     struct Sprite *scrollbar);
void sw_list_set_content_changed_notify(struct sw_widget *widget,
                                        void (*callback) (struct sw_widget
                                                          * widget,
                                                          void *data),
                                        void *data);

void sw_list_set_selection_changed_notify(struct sw_widget *widget,
                                          void (*callback) (struct sw_widget
                                                            * widget,
                                                            void *data),
                                          void *data);

/* ===== slider ==== */
struct sw_widget *sw_slider_create(struct sw_widget *parent, int width,
                                   int height, struct Sprite *sprite,
                                   bool vertical);
void sw_slider_set_slided_notify(struct sw_widget *widget,
                                 void (*callback) (struct sw_widget * widget,
                                                   void *data), void *data);
float sw_slider_get_offset(struct sw_widget *widget);
float sw_slider_get_width(struct sw_widget *widget);
void sw_slider_set_offset(struct sw_widget *widget, float offset);
void sw_slider_set_width(struct sw_widget *widget, float width);

/* ===== slider & list ==== */
void sw_update_vslider_from_list(struct sw_widget *slider,
                                 struct sw_widget *list);
void sw_update_hslider_from_list(struct sw_widget *slider,
                                 struct sw_widget *list);
void sw_update_list_from_vslider(struct sw_widget *list,
                                 struct sw_widget *slider);
void sw_update_list_from_hslider(struct sw_widget *list,
                                 struct sw_widget *slider);

/* ===== other ==== */
void sw_paint_all(void);
struct sw_widget *sw_create_root_window(void);
void sw_mainloop(void);
int sw_add_timeout(int msec, void (*callback) (void *data), void *data);
void sw_remove_timeout(int id);

#endif                          /* FC__WIDGET_H */
#ifndef FC_WIDGET_P_H
#define FC_WIDGET_P_H

#include "shared.h"
#include "widget.h"

#define BORDER_WIDTH    1

enum widget_face {
  WF_NORMAL,
  WF_SELECTED,
  WF_PRESSED,
  WF_DISABLED,
  WF_HIDDEN,
  NUM_WIDGET_FACES
};

struct sw_widget {
  struct sw_widget *parent;
  enum widget_type type;
  bool pressed;
  bool selected;
  bool disabled;
  bool dragged;
  bool passive;

  bool can_be_pressed;
  bool can_be_selected;
  bool can_be_dragged;

  bool needs_repaint;

  struct ct_point pos;
  struct ct_rect inner_bounds, outer_bounds;

  struct ct_string *tooltip;
  bool tooltip_shown;
  int tooltip_callback_id;

  enum color_ext background_color;      /* default COLOR_EXT_TRANSPARENT */
  struct Sprite *background_sprite;     /* default NULL */
  enum color_ext border_color;  /* default COLOR_EXT_TRANSPARENT */

  void (*destroy)(struct sw_widget *);
  void (*entered)(struct sw_widget *);
  void (*left)(struct sw_widget *);
  void (*click)(struct sw_widget *);
  void (*key)(struct sw_widget *, enum be_key key_type, char key);
  void (*draw)(struct sw_widget *);
  void (*draw_extra_background) (struct sw_widget *,
                                 const struct ct_rect * rect);
  void (*drag_start)(struct sw_widget *, const struct ct_point *mouse);
  void (*drag_move)(struct sw_widget *, const struct ct_point *start_position,
                    const struct ct_point *current_position);
  void (*drag_end)(struct sw_widget *);

  void (*click_start) (struct sw_widget *, const struct ct_point * mouse,
                       int button, int state, void *data);
  void *click_start_data;

  union {
    struct {
      struct widget_list children;
      struct osda *target;
      struct ct_string *title;
      struct ct_point pos_at_drag_start;
      int transparency;
      bool shown;
      struct ct_rect children_bounds;
      int inner_deco_height;
      int depth;
      struct sw_widget *list;
      struct osda *canvas_background;
      struct region_list to_flush;
    } window;
    struct {
      struct odsa *gfx;
    } icon;
    struct {
      struct ct_string *text[NUM_WIDGET_FACES];
      struct ct_point text_offset[NUM_WIDGET_FACES];

      struct Sprite *sprite_faces[NUM_WIDGET_FACES];
      struct ct_point sprite_faces_offset[NUM_WIDGET_FACES];
      struct Sprite *sprite_non_faces;
      struct ct_point sprite_non_faces_offset;
      struct osda *background_faces[NUM_WIDGET_FACES];
      void (*callback) (struct sw_widget * widget, void *data);
      void *callback_data;
    } button;
    struct {
      struct ct_string *template;
      char *buffer;
      int cursor;
      int max_size;
    } edit;
    struct {
      struct ct_string *text;
    } label;
    struct {
      struct ct_point offset;
      struct sw_widget *window;
      void (*callback1) (struct sw_widget * widget, void *data);
      void *callback1_data;
      void (*callback2) (struct sw_widget * widget, void *data);
      void *callback2_data;
      int columns, rows;
      struct sw_widget **items;
      bool needs_layout;
      int *widths, *heights;
      int *start_x, *start_y;
      int selected_row;
      enum ws_alignment *column_alignments;
      bool *row_enabled;
    } list;
    struct {
      float width, offset, pos_at_drag_start;
      bool vertical;
      void (*callback) (struct sw_widget * widget, void *data);
      void *callback_data;
      struct Sprite *sprite_faces[NUM_WIDGET_FACES];
    } slider;
  } data;
};

extern struct sw_widget *root_window;
extern struct widget_list deferred_destroyed_widgets;

void handle_callbacks(void);
void get_select_timeout(struct timeval *timeout);

struct sw_widget *create_widget(struct sw_widget *parent,
                                enum widget_type type);
struct osda *get_osda(struct sw_widget *widget);
enum widget_face get_widget_face(struct sw_widget *widget);
void translate_point(struct sw_widget *widget, struct ct_point *dest,
                     const struct ct_point *src);
void inner_size_changed(struct sw_widget *widget);
void flush_all_to_screen(void);

void parent_needs_paint(struct sw_widget *widget);
void widget_needs_paint(struct sw_widget *widget);

void update_window(struct sw_widget *widget);
struct sw_widget *search_widget(struct sw_widget *widget,
                                const struct ct_point *pos);
void real_widget_destroy(struct sw_widget *widget);
void remove_all_from_window(struct sw_widget *widget);

void align(const struct ct_rect *bb, struct ct_rect *item,
           enum ws_alignment alignment);

#endif

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#7125) [FS] Widget set, Raimar Falke <=