UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2014 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <inttypes.h> 33 34 #include "tree.h" 35 36 #include "container.h" 37 #include "../common/object.h" 38 #include "../common/context.h" 39 #include <ucx/utils.h> 40 41 UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) { 42 // TODO: check if modelinfo is complete 43 44 Arg args[32]; 45 int n = 0; 46 47 // create scrolled window 48 UiContainer *ct = uic_get_current_container(obj); 49 Widget parent = ct->prepare(ct, args, &n, TRUE); 50 51 XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); 52 n++; 53 XtSetArg(args[n], XmNshadowThickness, 0); 54 n++; 55 Widget scrollw = XmCreateScrolledWindow(parent, "scroll_win", args, n); 56 ct->add(ct, scrollw); 57 XtManageChild(scrollw); 58 59 // create table headers 60 XmStringTable header = (XmStringTable)XtMalloc( 61 model->columns * sizeof(XmString)); 62 for(int i=0;i<model->columns;i++) { 63 header[i] = XmStringCreateLocalized(model->titles[i]); 64 } 65 n = 0; 66 XtSetArg(args[n], XmNdetailColumnHeading, header); 67 n++; 68 XtSetArg(args[n], XmNdetailColumnHeadingCount, model->columns); 69 n++; 70 71 // set res 72 XtSetArg(args[n], XmNlayoutType, XmDETAIL); 73 n++; 74 XtSetArg(args[n], XmNentryViewType, XmSMALL_ICON); 75 n++; 76 XtSetArg(args[n], XmNselectionPolicy, XmSINGLE_SELECT); 77 n++; 78 XtSetArg(args[n], XmNwidth, 600); 79 n++; 80 81 // create widget 82 //UiContainer *ct = uic_get_current_container(obj); 83 //Widget parent = ct->add(ct, args, &n); 84 85 Widget container = XmCreateContainer(scrollw, "table", args, n); 86 XtManageChild(container); 87 88 // add callbacks 89 UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); 90 event->obj = obj; 91 event->activate = cb.activate; 92 event->selection = cb.selection; 93 event->userdata = cb.userdata; 94 event->last_selection = NULL; 95 if(cb.selection) { 96 XtAddCallback( 97 container, 98 XmNselectionCallback, 99 (XtCallbackProc)ui_table_select_callback, 100 event); 101 } 102 if(cb.activate) { 103 XtAddCallback( 104 container, 105 XmNdefaultActionCallback, 106 (XtCallbackProc)ui_table_action_callback, 107 event); 108 } 109 110 // add initial data 111 UiList *list = var->value; 112 void *data = list->first(list); 113 int width = 0; 114 while(data) { 115 int w = ui_add_icon_gadget(container, model, data); 116 if(w > width) { 117 width = w; 118 } 119 data = list->next(list); 120 } 121 122 UiTableView *tableview = ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiTableView)); 123 tableview->widget = container; 124 tableview->var = var; 125 tableview->model = model; 126 127 // set new XmContainer width 128 XtVaSetValues(container, XmNwidth, width, NULL); 129 130 // cleanup 131 for(int i=0;i<model->columns;i++) { 132 XmStringFree(header[i]); 133 } 134 XtFree((char*)header); 135 136 return scrollw; 137 } 138 139 UIWIDGET ui_table(UiObject *obj, UiList *data, UiModel *model, UiListCallbacks cb) { 140 UiVar *var = malloc(sizeof(UiVar)); 141 var->value = data; 142 var->type = UI_VAR_SPECIAL; 143 return ui_table_var(obj, var, model, cb); 144 } 145 146 void ui_table_update(UiEvent *event, UiTableView *view) { 147 // clear container 148 Widget *children; 149 int nc; 150 151 XtVaGetValues( 152 view->widget, 153 XmNchildren, 154 &children, 155 XmNnumChildren, 156 &nc, 157 NULL); 158 159 for(int i=0;i<nc;i++) { 160 XtDestroyWidget(children[i]); 161 } 162 163 UiList *list = view->var->value; 164 165 void *data = list->first(list); 166 int width = 0; 167 while(data) { 168 int w = ui_add_icon_gadget(view->widget, view->model, data); 169 if(w > width) { 170 width = w; 171 } 172 data = list->next(list); 173 } 174 175 } 176 177 #define UI_COL_CHAR_WIDTH 12 178 179 int ui_add_icon_gadget(Widget container, UiModel *model, void *data) { 180 int width = 50; 181 182 if(model->columns == 0) { 183 return width; 184 } 185 186 XmString label = NULL; 187 Arg args[8]; 188 Boolean f; 189 // first column 190 if(model->types[0] != 12345678) { // TODO: icon/label type 191 char *str = ui_type_to_string( 192 model->types[0], 193 model->getvalue(data, 0), 194 &f); 195 196 // column width 197 width += strlen(str) * UI_COL_CHAR_WIDTH; 198 199 200 XmString label = XmStringCreateLocalized(str); 201 XtSetArg(args[0], XmNlabelString, label); 202 if(f) { 203 free(str); 204 } 205 } else { 206 // TODO 207 } 208 209 // remaining columns are the icon gadget details 210 XmStringTable details = (XmStringTable)XtMalloc( 211 (model->columns - 1) * sizeof(XmString)); 212 for(int i=1;i<model->columns;i++) { 213 char *str = ui_type_to_string( 214 model->types[i], 215 model->getvalue(data, i), 216 &f); 217 218 // column width 219 width += strlen(str) * UI_COL_CHAR_WIDTH; 220 221 details[i - 1] = XmStringCreateLocalized(str); 222 if(f) { 223 free(str); 224 } 225 } 226 XtSetArg(args[1], XmNdetail, details); 227 XtSetArg(args[2], XmNdetailCount, model->columns - 1); 228 XtSetArg(args[3], XmNshadowThickness, 0); 229 // create widget 230 Widget item = XmCreateIconGadget(container, "table_item", args, 4); 231 XtManageChild(item); 232 233 // cleanup 234 XmStringFree(label); 235 for(int i=0;i<model->columns-1;i++) { 236 XmStringFree(details[i]); 237 } 238 XtFree((char*)details); 239 240 return width; 241 } 242 243 char* ui_type_to_string(UiModelType type, void *data, Boolean *free) { 244 switch(type) { 245 case UI_STRING: *free = FALSE; return data; 246 case UI_INTEGER: { 247 *free = TRUE; 248 int *val = data; 249 sstr_t str = ucx_asprintf(ucx_default_allocator(), "%d", *val); 250 return str.ptr; 251 } 252 } 253 *free = FALSE; 254 return NULL; 255 } 256 257 void ui_table_action_callback( 258 Widget widget, 259 UiTreeEventData *event, 260 XmContainerSelectCallbackStruct *sel) 261 { 262 UiListSelection *selection = ui_list_selection(sel); 263 264 UiEvent e; 265 e.obj = event->obj; 266 e.window = event->obj->window; 267 e.document = event->obj->ctx->document; 268 e.eventdata = selection; 269 e.intval = selection->count > 0 ? selection->rows[0] : -1; 270 event->activate(&e, event->userdata); 271 272 free(event->last_selection->rows); 273 free(event->last_selection); 274 event->last_selection = selection; 275 } 276 277 void ui_table_select_callback( 278 Widget widget, 279 UiTreeEventData *event, 280 XmContainerSelectCallbackStruct *sel) 281 { 282 UiListSelection *selection = ui_list_selection(sel); 283 if(!ui_compare_list_selection(selection, event->last_selection)) { 284 UiEvent e; 285 e.obj = event->obj; 286 e.window = event->obj->window; 287 e.document = event->obj->ctx->document; 288 e.eventdata = selection; 289 e.intval = selection->count > 0 ? selection->rows[0] : -1; 290 event->selection(&e, event->userdata); 291 } 292 if(event->last_selection) { 293 free(event->last_selection->rows); 294 free(event->last_selection); 295 } 296 event->last_selection = selection; 297 } 298 299 UiListSelection* ui_list_selection(XmContainerSelectCallbackStruct *xs) { 300 UiListSelection *selection = malloc(sizeof(UiListSelection)); 301 selection->count = xs->selected_item_count; 302 selection->rows = calloc(selection->count, sizeof(int)); 303 for(int i=0;i<selection->count;i++) { 304 int index; 305 XtVaGetValues(xs->selected_items[i], XmNpositionIndex, &index, NULL); 306 selection->rows[i] = index; 307 } 308 return selection; 309 } 310 311 Boolean ui_compare_list_selection(UiListSelection *s1, UiListSelection *s2) { 312 if(!s1 || !s2) { 313 return FALSE; 314 } 315 if(s1->count != s2->count) { 316 return FALSE; 317 } 318 for(int i=0;i<s1->count;i++) { 319 if(s1->rows[i] != s2->rows[i]) { 320 return FALSE; 321 } 322 } 323 return TRUE; 324 } 325